notebooklm-sdk 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,18 @@
1
- # notebooklm-sdk
1
+ <div align="center">
2
+ <img src="https://cdn.worldvectorlogo.com/logos/google-notebooklm-logo-icon.svg" width="48" alt="NotebookLM SDK" />
3
+ <h1>notebooklm-sdk</h1>
2
4
 
3
- ### Automate NotebookLM from your code.
5
+ <p>Automate NotebookLM from your code.</p>
6
+
7
+ <p>Generate AI podcasts, chat with documents, run web research, and manage notebooks programmatically — from Node.js, Bun, or Deno.</p>
4
8
 
5
9
  [![npm version](https://img.shields.io/npm/v/notebooklm-sdk?style=flat-square)](https://www.npmjs.com/package/notebooklm-sdk)
6
10
  ![types](https://img.shields.io/npm/types/notebooklm-sdk?style=flat-square)
7
11
  ![license](https://img.shields.io/npm/l/notebooklm-sdk?style=flat-square)
8
12
 
9
- Generate AI podcasts, chat with documents, run web research, and manage notebooks programmatically — from Node.js, Bun, or Deno.
13
+ </div>
10
14
 
11
- > **Unofficial.** This SDK reverse-engineers the NotebookLM internal API. It may break when Google updates their service. Not affiliated with Google.
15
+ > _**Unofficial.** This SDK reverse-engineers the NotebookLM internal API. It may break when Google updates their service. Not affiliated with Google._
12
16
 
13
17
  TypeScript port of [notebooklm-py](https://github.com/teng-lin/notebooklm-py).
14
18
 
@@ -50,12 +54,12 @@ console.log(res.answer);
50
54
 
51
55
  ## Use cases
52
56
 
53
- - **Blog & content generation** — research a topic, import sources, generate a blog post or briefing doc automatically
57
+ - **Blog & content generation** — research a topic, import sources, generate a briefing doc automatically
54
58
  - **Content pipelines** — ingest articles or reports, generate a podcast or briefing doc on a schedule
55
59
  - **Research automation** — run web research, import results, and query them via chat
56
60
  - **Document Q&A bots** — feed documents into a notebook and build a chat interface on top
57
61
  - **Batch artifact generation** — generate quizzes, flashcards, or study guides from a library of sources
58
- - **Notebook management tools** — create, organize, and share notebooks programmatically
62
+ - **Notebook management** — create, organize, and share notebooks programmatically
59
63
 
60
64
  ## Authentication
61
65
 
@@ -96,7 +100,7 @@ const client = await NotebookLMClient.connect({
96
100
 
97
101
  > To get cookie values: open NotebookLM in Chrome → DevTools → Network → any request → copy the `Cookie` header.
98
102
 
99
- ## What you can build
103
+ **API surface**
100
104
 
101
105
  | API | What it does |
102
106
  | ----------- | ------------------------------------------------------- |
@@ -123,7 +127,7 @@ const client = await NotebookLMClient.connect({
123
127
  | Quiz | `createQuiz()` | Interactive HTML |
124
128
  | Data Table | `createDataTable()` | CSV (headers + rows) |
125
129
 
126
- [Full API reference](./DOCS.md)
130
+ [Full API reference](./DOCS.md)
127
131
 
128
132
  ## Examples
129
133
 
@@ -145,6 +149,15 @@ bun run examples/full-lifecycle.ts # create, add sources, chat, delete
145
149
  bun run examples/download.ts # download all completed artifacts
146
150
  ```
147
151
 
152
+ ## Requirements
153
+
154
+ - Node.js 18+ or Bun 1.0+
155
+ - A Google account with access to [NotebookLM](https://notebooklm.google.com)
156
+
157
+ ## Contributing
158
+
159
+ Issues and PRs welcome. If the API breaks after a Google update, please open an issue with the error and request/response details.
160
+
148
161
  ## License
149
162
 
150
- MIT · TypeScript port of [notebooklm-py](https://github.com/teng-lin/notebooklm-py)
163
+ MIT
@@ -36,6 +36,7 @@ declare function fetchTokens(cookies: CookieMap): Promise<{
36
36
  csrfToken: string;
37
37
  sessionId: string;
38
38
  }>;
39
+ declare function refreshAuthTokens(auth: AuthTokens): Promise<AuthTokens>;
39
40
  interface ConnectOptions {
40
41
  /** "; "-separated cookie string (e.g. "SID=abc; HSID=xyz") */
41
42
  cookies?: string;
@@ -52,4 +53,4 @@ interface ConnectOptions {
52
53
  }
53
54
  declare function connect(opts?: ConnectOptions): Promise<AuthTokens>;
54
55
 
55
- export { type AuthTokens as A, type CookieMap as C, type ConnectOptions as a, buildCookieHeader as b, buildGoogleCookieHeader as c, connect as d, loadCookiesFromMap as e, fetchTokens as f, loadCookiesFromObject as g, loadCookiesFromString as h, loadCookiesFromFile as l };
56
+ export { type AuthTokens as A, type CookieMap as C, type ConnectOptions as a, buildCookieHeader as b, buildGoogleCookieHeader as c, connect as d, loadCookiesFromMap as e, fetchTokens as f, loadCookiesFromObject as g, loadCookiesFromString as h, loadCookiesFromFile as l, refreshAuthTokens as r };
@@ -36,6 +36,7 @@ declare function fetchTokens(cookies: CookieMap): Promise<{
36
36
  csrfToken: string;
37
37
  sessionId: string;
38
38
  }>;
39
+ declare function refreshAuthTokens(auth: AuthTokens): Promise<AuthTokens>;
39
40
  interface ConnectOptions {
40
41
  /** "; "-separated cookie string (e.g. "SID=abc; HSID=xyz") */
41
42
  cookies?: string;
@@ -52,4 +53,4 @@ interface ConnectOptions {
52
53
  }
53
54
  declare function connect(opts?: ConnectOptions): Promise<AuthTokens>;
54
55
 
55
- export { type AuthTokens as A, type CookieMap as C, type ConnectOptions as a, buildCookieHeader as b, buildGoogleCookieHeader as c, connect as d, loadCookiesFromMap as e, fetchTokens as f, loadCookiesFromObject as g, loadCookiesFromString as h, loadCookiesFromFile as l };
56
+ export { type AuthTokens as A, type CookieMap as C, type ConnectOptions as a, buildCookieHeader as b, buildGoogleCookieHeader as c, connect as d, loadCookiesFromMap as e, fetchTokens as f, loadCookiesFromObject as g, loadCookiesFromString as h, loadCookiesFromFile as l, refreshAuthTokens as r };
package/dist/auth.cjs CHANGED
@@ -117,6 +117,12 @@ async function fetchTokens(cookies) {
117
117
  const sessionId = extractSessionId(html, finalUrl);
118
118
  return { csrfToken, sessionId };
119
119
  }
120
+ async function refreshAuthTokens(auth) {
121
+ const { csrfToken, sessionId } = await fetchTokens(auth.cookies);
122
+ auth.csrfToken = csrfToken;
123
+ auth.sessionId = sessionId;
124
+ return auth;
125
+ }
120
126
  function extractCsrfToken(html, finalUrl) {
121
127
  const match = /"SNlM0e"\s*:\s*"([^"]+)"/.exec(html);
122
128
  if (!match?.[1]) {
@@ -247,5 +253,6 @@ exports.loadCookiesFromMap = loadCookiesFromMap;
247
253
  exports.loadCookiesFromObject = loadCookiesFromObject;
248
254
  exports.loadCookiesFromString = loadCookiesFromString;
249
255
  exports.login = login;
256
+ exports.refreshAuthTokens = refreshAuthTokens;
250
257
  //# sourceMappingURL=auth.cjs.map
251
258
  //# sourceMappingURL=auth.cjs.map
package/dist/auth.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/errors.ts","../src/auth.ts","../src/auth/browser.ts"],"names":["join","homedir","readFileSync","existsSync","DEFAULT_SESSION_FILE","NOTEBOOKLM_URL","chromium","mkdirSync"],"mappings":"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","file":"auth.cjs","sourcesContent":["/**\n * All exceptions for notebooklm-sdk.\n *\n * All errors extend NotebookLMError so you can catch everything with:\n * try { ... } catch (e) { if (e instanceof NotebookLMError) ... }\n */\n\nexport class NotebookLMError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Network (transport-level, before RPC processing)\n// ---------------------------------------------------------------------------\n\nexport class NetworkError extends NotebookLMError {\n readonly methodId?: string;\n readonly originalError?: Error;\n\n constructor(message: string, opts: { methodId?: string; originalError?: Error } = {}) {\n super(message);\n this.methodId = opts.methodId;\n this.originalError = opts.originalError;\n }\n}\n\nexport class RPCTimeoutError extends NetworkError {}\n\n// ---------------------------------------------------------------------------\n// RPC Protocol (after connection established)\n// ---------------------------------------------------------------------------\n\nexport class RPCError extends NotebookLMError {\n readonly methodId?: string;\n readonly rawResponse?: string;\n readonly rpcCode?: string | number;\n readonly foundIds: string[];\n\n constructor(\n message: string,\n opts: {\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message);\n this.methodId = opts.methodId;\n this.rawResponse = opts.rawResponse ? opts.rawResponse.slice(0, 500) : undefined;\n this.rpcCode = opts.rpcCode;\n this.foundIds = opts.foundIds ?? [];\n }\n}\n\nexport class AuthError extends RPCError {}\n\nexport class RateLimitError extends RPCError {\n readonly retryAfter?: number;\n\n constructor(\n message: string,\n opts: {\n retryAfter?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message, opts);\n this.retryAfter = opts.retryAfter;\n }\n}\n\nexport class ServerError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\nexport class ClientError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Notebooks\n// ---------------------------------------------------------------------------\n\nexport class NotebookError extends NotebookLMError {}\n\nexport class NotebookNotFoundError extends NotebookError {\n readonly notebookId: string;\n\n constructor(notebookId: string) {\n super(`Notebook not found: ${notebookId}`);\n this.notebookId = notebookId;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Sources\n// ---------------------------------------------------------------------------\n\nexport class SourceError extends NotebookLMError {}\n\nexport class SourceNotFoundError extends SourceError {\n readonly sourceId: string;\n\n constructor(sourceId: string) {\n super(`Source not found: ${sourceId}`);\n this.sourceId = sourceId;\n }\n}\n\nexport class SourceAddError extends SourceError {\n readonly url: string;\n readonly cause?: Error;\n\n constructor(url: string, opts: { cause?: Error; message?: string } = {}) {\n super(\n opts.message ??\n `Failed to add source: ${url}\\n` +\n \"Possible causes:\\n\" +\n \" - URL is invalid or inaccessible\\n\" +\n \" - Content is behind a paywall or requires authentication\\n\" +\n \" - Rate limiting or quota exceeded\",\n );\n this.url = url;\n this.cause = opts.cause;\n }\n}\n\nexport class SourceProcessingError extends SourceError {\n readonly sourceId: string;\n readonly status: number;\n\n constructor(sourceId: string, status = 3, message?: string) {\n super(message ?? `Source ${sourceId} failed to process`);\n this.sourceId = sourceId;\n this.status = status;\n }\n}\n\nexport class SourceTimeoutError extends SourceError {\n readonly sourceId: string;\n readonly timeout: number;\n readonly lastStatus?: number;\n\n constructor(sourceId: string, timeout: number, lastStatus?: number) {\n const statusInfo = lastStatus != null ? ` (last status: ${lastStatus})` : \"\";\n super(`Source ${sourceId} not ready after ${timeout.toFixed(1)}s${statusInfo}`);\n this.sourceId = sourceId;\n this.timeout = timeout;\n this.lastStatus = lastStatus;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Artifacts\n// ---------------------------------------------------------------------------\n\nexport class ArtifactError extends NotebookLMError {}\n\nexport class ArtifactNotFoundError extends ArtifactError {\n readonly artifactId: string;\n readonly artifactType?: string;\n\n constructor(artifactId: string, artifactType?: string) {\n const typeInfo = artifactType ? ` ${artifactType}` : \"\";\n super(`${typeInfo.trim() || \"Artifact\"} ${artifactId} not found`);\n this.artifactId = artifactId;\n this.artifactType = artifactType;\n }\n}\n\nexport class ArtifactNotReadyError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly status?: string;\n\n constructor(artifactType: string, opts: { artifactId?: string; status?: string } = {}) {\n const base = opts.artifactId\n ? `${artifactType} artifact ${opts.artifactId} is not ready`\n : `No completed ${artifactType} found`;\n const statusInfo = opts.status ? ` (status: ${opts.status})` : \"\";\n super(`${base}${statusInfo}`);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.status = opts.status;\n }\n}\n\nexport class ArtifactParseError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to parse ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\nexport class ArtifactDownloadError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to download ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Chat\n// ---------------------------------------------------------------------------\n\nexport class ChatError extends NotebookLMError {}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { AuthError } from \"./types/errors.js\";\n\n/** Default session file written by `npx notebooklm-sdk login`. */\nconst DEFAULT_SESSION_FILE = join(homedir(), \".notebooklm\", \"session.json\");\n\nexport interface CookieMap {\n [key: string]: string;\n}\n\nexport interface AuthTokens {\n cookies: CookieMap;\n csrfToken: string;\n sessionId: string;\n cookieHeader: string;\n /** Cookie header containing only .google.com domain cookies — for media downloads */\n googleCookieHeader: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cookie loading\n// ---------------------------------------------------------------------------\n\n/** Load cookies from a Playwright storage_state.json file. */\nexport function loadCookiesFromFile(filePath: string): CookieMap {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n throw new AuthError(`Session file not found: ${filePath}\\nRun: npx notebooklm-sdk login`);\n }\n return extractCookiesFromStorageState(JSON.parse(raw));\n}\n\n/** Load cookies from a raw Playwright storage state object. */\nexport function loadCookiesFromObject(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n return extractCookiesFromStorageState(storageState);\n}\n\n/** Build a cookie header containing only .google.com domain cookies (for media downloads). */\nexport function buildGoogleCookieHeader(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): string {\n const map: CookieMap = {};\n for (const c of storageState.cookies ?? []) {\n if (c.domain === \".google.com\" && c.name && c.value) {\n map[c.name] = map[c.name] ?? c.value;\n }\n }\n return buildCookieHeader(map);\n}\n\n/** Load cookies from a flat cookie map (already parsed). */\nexport function loadCookiesFromMap(map: CookieMap): CookieMap {\n return { ...map };\n}\n\n/** Load cookies from a \"; \"-separated cookie string (e.g. process.env.NOTEBOOKLM_COOKIES). */\nexport function loadCookiesFromString(cookieStr: string): CookieMap {\n const map: CookieMap = {};\n for (const part of cookieStr.split(/;\\s*/)) {\n const idx = part.indexOf(\"=\");\n if (idx > 0) {\n const name = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (name) map[name] = value;\n }\n }\n return map;\n}\n\nfunction extractCookiesFromStorageState(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n const cookies: CookieMap = {};\n const domainTrack: Record<string, string> = {};\n\n for (const cookie of storageState.cookies ?? []) {\n const { domain, name, value } = cookie;\n if (!isAllowedDomain(domain) || !name) continue;\n\n const isBase = domain === \".google.com\";\n if (!(name in cookies) || isBase) {\n cookies[name] = value;\n domainTrack[name] = domain;\n }\n }\n\n if (!cookies[\"SID\"]) {\n throw new AuthError(\n \"Missing required cookie: SID. Session may be invalid or expired.\\nRun: npx notebooklm-sdk login\",\n );\n }\n return cookies;\n}\n\nfunction isAllowedDomain(domain: string): boolean {\n if (\n domain === \".google.com\" ||\n domain === \"notebooklm.google.com\" ||\n domain === \".googleusercontent.com\"\n ) {\n return true;\n }\n if (domain.startsWith(\".google.\")) {\n return true; // Allow all regional Google domains\n }\n return false;\n}\n\nexport function buildCookieHeader(cookies: CookieMap): string {\n return Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \");\n}\n\n// ---------------------------------------------------------------------------\n// Token fetching\n// ---------------------------------------------------------------------------\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\n\nexport async function fetchTokens(\n cookies: CookieMap,\n): Promise<{ csrfToken: string; sessionId: string }> {\n const cookieHeader = buildCookieHeader(cookies);\n\n const response = await fetch(NOTEBOOKLM_URL, {\n headers: { Cookie: cookieHeader },\n redirect: \"follow\",\n });\n\n if (!response.ok) {\n throw new AuthError(`Failed to fetch NotebookLM page: HTTP ${response.status}`);\n }\n\n const finalUrl = response.url;\n if (isGoogleAuthRedirect(finalUrl)) {\n throw new AuthError(`Redirected to login page: ${finalUrl}. Cookies may be expired.`);\n }\n\n const html = await response.text();\n const csrfToken = extractCsrfToken(html, finalUrl);\n const sessionId = extractSessionId(html, finalUrl);\n\n return { csrfToken, sessionId };\n}\n\nfunction extractCsrfToken(html: string, finalUrl: string): string {\n const match = /\"SNlM0e\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"CSRF token (SNlM0e) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction extractSessionId(html: string, finalUrl: string): string {\n const match = /\"FdrFJe\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"Session ID (FdrFJe) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction isGoogleAuthRedirect(url: string): boolean {\n return url.includes(\"accounts.google.com\") || url.includes(\"signin\");\n}\n\n// ---------------------------------------------------------------------------\n// Connect options\n// ---------------------------------------------------------------------------\n\nexport interface ConnectOptions {\n /** \"; \"-separated cookie string (e.g. \"SID=abc; HSID=xyz\") */\n cookies?: string;\n /** Path to Playwright storage_state.json */\n cookiesFile?: string;\n /** Pre-parsed cookie map */\n cookiesObject?: CookieMap | { cookies?: Array<{ name: string; value: string; domain: string }> };\n}\n\nexport async function connect(opts: ConnectOptions = {}): Promise<AuthTokens> {\n let cookieMap: CookieMap;\n let googleCookieHeader: string | null = null;\n\n if (opts.cookies) {\n cookieMap = loadCookiesFromString(opts.cookies);\n } else if (opts.cookiesFile) {\n cookieMap = loadCookiesFromFile(opts.cookiesFile);\n } else if (opts.cookiesObject) {\n if (\"cookies\" in opts.cookiesObject && Array.isArray(opts.cookiesObject.cookies)) {\n const storageState = opts.cookiesObject as {\n cookies: Array<{ name: string; value: string; domain: string }>;\n };\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else {\n cookieMap = loadCookiesFromMap(opts.cookiesObject as CookieMap);\n }\n } else {\n // Auto-discovery: ~/.notebooklm/session.json → ./storage_state.json → env var\n const envCookies = process.env[\"NOTEBOOKLM_COOKIES\"];\n const envFile = process.env[\"NOTEBOOKLM_COOKIES_FILE\"];\n if (envFile) {\n cookieMap = loadCookiesFromFile(envFile);\n } else if (existsSync(DEFAULT_SESSION_FILE)) {\n const raw = readFileSync(DEFAULT_SESSION_FILE, \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (existsSync(\"storage_state.json\")) {\n const raw = readFileSync(\"storage_state.json\", \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (envCookies) {\n cookieMap = loadCookiesFromString(envCookies);\n } else {\n throw new AuthError(\"No session found. Run: npx notebooklm-sdk login\");\n }\n }\n\n const { csrfToken, sessionId } = await fetchTokens(cookieMap);\n const cookieHeader = buildCookieHeader(cookieMap);\n\n return {\n cookies: cookieMap,\n csrfToken,\n sessionId,\n cookieHeader,\n googleCookieHeader: googleCookieHeader ?? cookieHeader,\n };\n}\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type BrowserContext, chromium, type Page } from \"playwright\";\nimport { type CookieMap, loadCookiesFromObject } from \"../auth.js\";\n\n/** Default directory for storing NotebookLM session files (~/.notebooklm). */\nexport const DEFAULT_SESSION_DIR = join(homedir(), \".notebooklm\");\n/** Default session file path (~/.notebooklm/session.json). */\nexport const DEFAULT_SESSION_FILE = join(DEFAULT_SESSION_DIR, \"session.json\");\n\nexport interface LoginOptions {\n /**\n * Path to a directory for a persistent browser profile.\n * Defaults to ~/.notebooklm/.auth_profile.\n */\n persistFolder?: string;\n /**\n * Browser type to use. Default is \"chromium\".\n */\n browserType?: \"chromium\" | \"msedge\";\n /**\n * Whether to run the browser in headless mode. Default is false.\n * Headless login is usually blocked by Google, so this is mostly for testing or refreshes.\n */\n headless?: boolean;\n}\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\nconst GOOGLE_ACCOUNTS_URL = \"https://accounts.google.com/\";\n\n/**\n * Log in to NotebookLM via a headful browser window.\n *\n * Flow:\n * 1. Opens browser to NotebookLM.\n * 2. If already logged in (via persistFolder), it proceeds.\n * 3. If not, it waits for the user to reach the home page.\n * 4. Captures cookies and returns them.\n */\nexport async function login(opts: LoginOptions = {}): Promise<{\n cookies: CookieMap;\n storageState: any;\n cookieHeader: string;\n}> {\n const {\n persistFolder = join(DEFAULT_SESSION_DIR, \".auth_profile\"),\n headless = false,\n browserType = \"chromium\",\n } = opts;\n\n // Pre-flight: verify Playwright browser is installed\n try {\n chromium.executablePath();\n } catch {\n throw new Error(\"Playwright browser not found. Run: npx playwright install chromium\");\n }\n\n // Ensure the session directory exists\n if (!existsSync(DEFAULT_SESSION_DIR)) {\n mkdirSync(DEFAULT_SESSION_DIR, { recursive: true });\n }\n\n let context: BrowserContext;\n\n const launchOptions = {\n headless,\n args: [\"--disable-blink-features=AutomationControlled\"],\n };\n\n context = await chromium.launchPersistentContext(persistFolder, {\n ...launchOptions,\n channel: browserType === \"msedge\" ? \"msedge\" : undefined,\n });\n\n const page = context.pages()[0] || (await context.newPage());\n await page.goto(NOTEBOOKLM_URL);\n\n // Check if we are on the login page\n if (page.url().includes(\"accounts.google.com\")) {\n console.log(\"Please log in to Google in the browser window...\");\n\n // Wait for navigation back to NotebookLM or successful login indicator\n // We poll until the URL includes notebooklm.google.com and it's not a generic landing page\n await page.waitForURL(\n (url) => {\n return url.hostname === \"notebooklm.google.com\" && !url.pathname.includes(\"/login\");\n },\n { timeout: 0 },\n ); // No timeout, wait for user\n }\n\n // Ensure we are fully loaded on the accounts domain too to capture those cookies\n await page.goto(GOOGLE_ACCOUNTS_URL, { waitUntil: \"load\" });\n await page.goto(NOTEBOOKLM_URL, { waitUntil: \"load\" });\n\n const storageState = await context.storageState();\n const cookies = loadCookiesFromObject(storageState as any);\n\n await context.close();\n\n return {\n cookies,\n storageState,\n cookieHeader: Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \"),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/types/errors.ts","../src/auth.ts","../src/auth/browser.ts"],"names":["join","homedir","readFileSync","existsSync","DEFAULT_SESSION_FILE","NOTEBOOKLM_URL","chromium","mkdirSync"],"mappings":"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","file":"auth.cjs","sourcesContent":["/**\n * All exceptions for notebooklm-sdk.\n *\n * All errors extend NotebookLMError so you can catch everything with:\n * try { ... } catch (e) { if (e instanceof NotebookLMError) ... }\n */\n\nexport class NotebookLMError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Network (transport-level, before RPC processing)\n// ---------------------------------------------------------------------------\n\nexport class NetworkError extends NotebookLMError {\n readonly methodId?: string;\n readonly originalError?: Error;\n\n constructor(message: string, opts: { methodId?: string; originalError?: Error } = {}) {\n super(message);\n this.methodId = opts.methodId;\n this.originalError = opts.originalError;\n }\n}\n\nexport class RPCTimeoutError extends NetworkError {}\n\n// ---------------------------------------------------------------------------\n// RPC Protocol (after connection established)\n// ---------------------------------------------------------------------------\n\nexport class RPCError extends NotebookLMError {\n readonly methodId?: string;\n readonly rawResponse?: string;\n readonly rpcCode?: string | number;\n readonly foundIds: string[];\n\n constructor(\n message: string,\n opts: {\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message);\n this.methodId = opts.methodId;\n this.rawResponse = opts.rawResponse ? opts.rawResponse.slice(0, 500) : undefined;\n this.rpcCode = opts.rpcCode;\n this.foundIds = opts.foundIds ?? [];\n }\n}\n\nexport class AuthError extends RPCError {}\n\nexport class RateLimitError extends RPCError {\n readonly retryAfter?: number;\n\n constructor(\n message: string,\n opts: {\n retryAfter?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message, opts);\n this.retryAfter = opts.retryAfter;\n }\n}\n\nexport class ServerError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\nexport class ClientError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Notebooks\n// ---------------------------------------------------------------------------\n\nexport class NotebookError extends NotebookLMError {}\n\nexport class NotebookNotFoundError extends NotebookError {\n readonly notebookId: string;\n\n constructor(notebookId: string) {\n super(`Notebook not found: ${notebookId}`);\n this.notebookId = notebookId;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Sources\n// ---------------------------------------------------------------------------\n\nexport class SourceError extends NotebookLMError {}\n\nexport class SourceNotFoundError extends SourceError {\n readonly sourceId: string;\n\n constructor(sourceId: string) {\n super(`Source not found: ${sourceId}`);\n this.sourceId = sourceId;\n }\n}\n\nexport class SourceAddError extends SourceError {\n readonly url: string;\n readonly cause?: Error;\n\n constructor(url: string, opts: { cause?: Error; message?: string } = {}) {\n super(\n opts.message ??\n `Failed to add source: ${url}\\n` +\n \"Possible causes:\\n\" +\n \" - URL is invalid or inaccessible\\n\" +\n \" - Content is behind a paywall or requires authentication\\n\" +\n \" - Rate limiting or quota exceeded\",\n );\n this.url = url;\n this.cause = opts.cause;\n }\n}\n\nexport class SourceProcessingError extends SourceError {\n readonly sourceId: string;\n readonly status: number;\n\n constructor(sourceId: string, status = 3, message?: string) {\n super(message ?? `Source ${sourceId} failed to process`);\n this.sourceId = sourceId;\n this.status = status;\n }\n}\n\nexport class SourceTimeoutError extends SourceError {\n readonly sourceId: string;\n readonly timeout: number;\n readonly lastStatus?: number;\n\n constructor(sourceId: string, timeout: number, lastStatus?: number) {\n const statusInfo = lastStatus != null ? ` (last status: ${lastStatus})` : \"\";\n super(`Source ${sourceId} not ready after ${timeout.toFixed(1)}s${statusInfo}`);\n this.sourceId = sourceId;\n this.timeout = timeout;\n this.lastStatus = lastStatus;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Artifacts\n// ---------------------------------------------------------------------------\n\nexport class ArtifactError extends NotebookLMError {}\n\nexport class ArtifactNotFoundError extends ArtifactError {\n readonly artifactId: string;\n readonly artifactType?: string;\n\n constructor(artifactId: string, artifactType?: string) {\n const typeInfo = artifactType ? ` ${artifactType}` : \"\";\n super(`${typeInfo.trim() || \"Artifact\"} ${artifactId} not found`);\n this.artifactId = artifactId;\n this.artifactType = artifactType;\n }\n}\n\nexport class ArtifactNotReadyError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly status?: string;\n\n constructor(artifactType: string, opts: { artifactId?: string; status?: string } = {}) {\n const base = opts.artifactId\n ? `${artifactType} artifact ${opts.artifactId} is not ready`\n : `No completed ${artifactType} found`;\n const statusInfo = opts.status ? ` (status: ${opts.status})` : \"\";\n super(`${base}${statusInfo}`);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.status = opts.status;\n }\n}\n\nexport class ArtifactParseError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to parse ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\nexport class ArtifactDownloadError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to download ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Chat\n// ---------------------------------------------------------------------------\n\nexport class ChatError extends NotebookLMError {}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { AuthError } from \"./types/errors.js\";\n\n/** Default session file written by `npx notebooklm-sdk login`. */\nconst DEFAULT_SESSION_FILE = join(homedir(), \".notebooklm\", \"session.json\");\n\nexport interface CookieMap {\n [key: string]: string;\n}\n\nexport interface AuthTokens {\n cookies: CookieMap;\n csrfToken: string;\n sessionId: string;\n cookieHeader: string;\n /** Cookie header containing only .google.com domain cookies — for media downloads */\n googleCookieHeader: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cookie loading\n// ---------------------------------------------------------------------------\n\n/** Load cookies from a Playwright storage_state.json file. */\nexport function loadCookiesFromFile(filePath: string): CookieMap {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n throw new AuthError(`Session file not found: ${filePath}\\nRun: npx notebooklm-sdk login`);\n }\n return extractCookiesFromStorageState(JSON.parse(raw));\n}\n\n/** Load cookies from a raw Playwright storage state object. */\nexport function loadCookiesFromObject(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n return extractCookiesFromStorageState(storageState);\n}\n\n/** Build a cookie header containing only .google.com domain cookies (for media downloads). */\nexport function buildGoogleCookieHeader(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): string {\n const map: CookieMap = {};\n for (const c of storageState.cookies ?? []) {\n if (c.domain === \".google.com\" && c.name && c.value) {\n map[c.name] = map[c.name] ?? c.value;\n }\n }\n return buildCookieHeader(map);\n}\n\n/** Load cookies from a flat cookie map (already parsed). */\nexport function loadCookiesFromMap(map: CookieMap): CookieMap {\n return { ...map };\n}\n\n/** Load cookies from a \"; \"-separated cookie string (e.g. process.env.NOTEBOOKLM_COOKIES). */\nexport function loadCookiesFromString(cookieStr: string): CookieMap {\n const map: CookieMap = {};\n for (const part of cookieStr.split(/;\\s*/)) {\n const idx = part.indexOf(\"=\");\n if (idx > 0) {\n const name = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (name) map[name] = value;\n }\n }\n return map;\n}\n\nfunction extractCookiesFromStorageState(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n const cookies: CookieMap = {};\n const domainTrack: Record<string, string> = {};\n\n for (const cookie of storageState.cookies ?? []) {\n const { domain, name, value } = cookie;\n if (!isAllowedDomain(domain) || !name) continue;\n\n const isBase = domain === \".google.com\";\n if (!(name in cookies) || isBase) {\n cookies[name] = value;\n domainTrack[name] = domain;\n }\n }\n\n if (!cookies[\"SID\"]) {\n throw new AuthError(\n \"Missing required cookie: SID. Session may be invalid or expired.\\nRun: npx notebooklm-sdk login\",\n );\n }\n return cookies;\n}\n\nfunction isAllowedDomain(domain: string): boolean {\n if (\n domain === \".google.com\" ||\n domain === \"notebooklm.google.com\" ||\n domain === \".googleusercontent.com\"\n ) {\n return true;\n }\n if (domain.startsWith(\".google.\")) {\n return true; // Allow all regional Google domains\n }\n return false;\n}\n\nexport function buildCookieHeader(cookies: CookieMap): string {\n return Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \");\n}\n\n// ---------------------------------------------------------------------------\n// Token fetching\n// ---------------------------------------------------------------------------\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\n\nexport async function fetchTokens(\n cookies: CookieMap,\n): Promise<{ csrfToken: string; sessionId: string }> {\n const cookieHeader = buildCookieHeader(cookies);\n\n const response = await fetch(NOTEBOOKLM_URL, {\n headers: { Cookie: cookieHeader },\n redirect: \"follow\",\n });\n\n if (!response.ok) {\n throw new AuthError(`Failed to fetch NotebookLM page: HTTP ${response.status}`);\n }\n\n const finalUrl = response.url;\n if (isGoogleAuthRedirect(finalUrl)) {\n throw new AuthError(`Redirected to login page: ${finalUrl}. Cookies may be expired.`);\n }\n\n const html = await response.text();\n const csrfToken = extractCsrfToken(html, finalUrl);\n const sessionId = extractSessionId(html, finalUrl);\n\n return { csrfToken, sessionId };\n}\n\nexport async function refreshAuthTokens(auth: AuthTokens): Promise<AuthTokens> {\n const { csrfToken, sessionId } = await fetchTokens(auth.cookies);\n auth.csrfToken = csrfToken;\n auth.sessionId = sessionId;\n return auth;\n}\n\nfunction extractCsrfToken(html: string, finalUrl: string): string {\n const match = /\"SNlM0e\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"CSRF token (SNlM0e) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction extractSessionId(html: string, finalUrl: string): string {\n const match = /\"FdrFJe\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"Session ID (FdrFJe) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction isGoogleAuthRedirect(url: string): boolean {\n return url.includes(\"accounts.google.com\") || url.includes(\"signin\");\n}\n\n// ---------------------------------------------------------------------------\n// Connect options\n// ---------------------------------------------------------------------------\n\nexport interface ConnectOptions {\n /** \"; \"-separated cookie string (e.g. \"SID=abc; HSID=xyz\") */\n cookies?: string;\n /** Path to Playwright storage_state.json */\n cookiesFile?: string;\n /** Pre-parsed cookie map */\n cookiesObject?: CookieMap | { cookies?: Array<{ name: string; value: string; domain: string }> };\n}\n\nexport async function connect(opts: ConnectOptions = {}): Promise<AuthTokens> {\n let cookieMap: CookieMap;\n let googleCookieHeader: string | null = null;\n\n if (opts.cookies) {\n cookieMap = loadCookiesFromString(opts.cookies);\n } else if (opts.cookiesFile) {\n cookieMap = loadCookiesFromFile(opts.cookiesFile);\n } else if (opts.cookiesObject) {\n if (\"cookies\" in opts.cookiesObject && Array.isArray(opts.cookiesObject.cookies)) {\n const storageState = opts.cookiesObject as {\n cookies: Array<{ name: string; value: string; domain: string }>;\n };\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else {\n cookieMap = loadCookiesFromMap(opts.cookiesObject as CookieMap);\n }\n } else {\n // Auto-discovery: ~/.notebooklm/session.json → ./storage_state.json → env var\n const envCookies = process.env[\"NOTEBOOKLM_COOKIES\"];\n const envFile = process.env[\"NOTEBOOKLM_COOKIES_FILE\"];\n if (envFile) {\n cookieMap = loadCookiesFromFile(envFile);\n } else if (existsSync(DEFAULT_SESSION_FILE)) {\n const raw = readFileSync(DEFAULT_SESSION_FILE, \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (existsSync(\"storage_state.json\")) {\n const raw = readFileSync(\"storage_state.json\", \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (envCookies) {\n cookieMap = loadCookiesFromString(envCookies);\n } else {\n throw new AuthError(\"No session found. Run: npx notebooklm-sdk login\");\n }\n }\n\n const { csrfToken, sessionId } = await fetchTokens(cookieMap);\n const cookieHeader = buildCookieHeader(cookieMap);\n\n return {\n cookies: cookieMap,\n csrfToken,\n sessionId,\n cookieHeader,\n googleCookieHeader: googleCookieHeader ?? cookieHeader,\n };\n}\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type BrowserContext, chromium, type Page } from \"playwright\";\nimport { type CookieMap, loadCookiesFromObject } from \"../auth.js\";\n\n/** Default directory for storing NotebookLM session files (~/.notebooklm). */\nexport const DEFAULT_SESSION_DIR = join(homedir(), \".notebooklm\");\n/** Default session file path (~/.notebooklm/session.json). */\nexport const DEFAULT_SESSION_FILE = join(DEFAULT_SESSION_DIR, \"session.json\");\n\nexport interface LoginOptions {\n /**\n * Path to a directory for a persistent browser profile.\n * Defaults to ~/.notebooklm/.auth_profile.\n */\n persistFolder?: string;\n /**\n * Browser type to use. Default is \"chromium\".\n */\n browserType?: \"chromium\" | \"msedge\";\n /**\n * Whether to run the browser in headless mode. Default is false.\n * Headless login is usually blocked by Google, so this is mostly for testing or refreshes.\n */\n headless?: boolean;\n}\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\nconst GOOGLE_ACCOUNTS_URL = \"https://accounts.google.com/\";\n\n/**\n * Log in to NotebookLM via a headful browser window.\n *\n * Flow:\n * 1. Opens browser to NotebookLM.\n * 2. If already logged in (via persistFolder), it proceeds.\n * 3. If not, it waits for the user to reach the home page.\n * 4. Captures cookies and returns them.\n */\nexport async function login(opts: LoginOptions = {}): Promise<{\n cookies: CookieMap;\n storageState: any;\n cookieHeader: string;\n}> {\n const {\n persistFolder = join(DEFAULT_SESSION_DIR, \".auth_profile\"),\n headless = false,\n browserType = \"chromium\",\n } = opts;\n\n // Pre-flight: verify Playwright browser is installed\n try {\n chromium.executablePath();\n } catch {\n throw new Error(\"Playwright browser not found. Run: npx playwright install chromium\");\n }\n\n // Ensure the session directory exists\n if (!existsSync(DEFAULT_SESSION_DIR)) {\n mkdirSync(DEFAULT_SESSION_DIR, { recursive: true });\n }\n\n let context: BrowserContext;\n\n const launchOptions = {\n headless,\n args: [\"--disable-blink-features=AutomationControlled\"],\n };\n\n context = await chromium.launchPersistentContext(persistFolder, {\n ...launchOptions,\n channel: browserType === \"msedge\" ? \"msedge\" : undefined,\n });\n\n const page = context.pages()[0] || (await context.newPage());\n await page.goto(NOTEBOOKLM_URL);\n\n // Check if we are on the login page\n if (page.url().includes(\"accounts.google.com\")) {\n console.log(\"Please log in to Google in the browser window...\");\n\n // Wait for navigation back to NotebookLM or successful login indicator\n // We poll until the URL includes notebooklm.google.com and it's not a generic landing page\n await page.waitForURL(\n (url) => {\n return url.hostname === \"notebooklm.google.com\" && !url.pathname.includes(\"/login\");\n },\n { timeout: 0 },\n ); // No timeout, wait for user\n }\n\n // Ensure we are fully loaded on the accounts domain too to capture those cookies\n await page.goto(GOOGLE_ACCOUNTS_URL, { waitUntil: \"load\" });\n await page.goto(NOTEBOOKLM_URL, { waitUntil: \"load\" });\n\n const storageState = await context.storageState();\n const cookies = loadCookiesFromObject(storageState as any);\n\n await context.close();\n\n return {\n cookies,\n storageState,\n cookieHeader: Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \"),\n };\n}\n"]}
package/dist/auth.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CookieMap } from './auth-Dxsm8894.cjs';
2
- export { A as AuthTokens, a as ConnectOptions, b as buildCookieHeader, c as buildGoogleCookieHeader, d as connect, f as fetchTokens, l as loadCookiesFromFile, e as loadCookiesFromMap, g as loadCookiesFromObject, h as loadCookiesFromString } from './auth-Dxsm8894.cjs';
1
+ import { C as CookieMap } from './auth-BlG6x47F.cjs';
2
+ export { A as AuthTokens, a as ConnectOptions, b as buildCookieHeader, c as buildGoogleCookieHeader, d as connect, f as fetchTokens, l as loadCookiesFromFile, e as loadCookiesFromMap, g as loadCookiesFromObject, h as loadCookiesFromString, r as refreshAuthTokens } from './auth-BlG6x47F.cjs';
3
3
 
4
4
  /** Default directory for storing NotebookLM session files (~/.notebooklm). */
5
5
  declare const DEFAULT_SESSION_DIR: string;
package/dist/auth.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CookieMap } from './auth-Dxsm8894.js';
2
- export { A as AuthTokens, a as ConnectOptions, b as buildCookieHeader, c as buildGoogleCookieHeader, d as connect, f as fetchTokens, l as loadCookiesFromFile, e as loadCookiesFromMap, g as loadCookiesFromObject, h as loadCookiesFromString } from './auth-Dxsm8894.js';
1
+ import { C as CookieMap } from './auth-BlG6x47F.js';
2
+ export { A as AuthTokens, a as ConnectOptions, b as buildCookieHeader, c as buildGoogleCookieHeader, d as connect, f as fetchTokens, l as loadCookiesFromFile, e as loadCookiesFromMap, g as loadCookiesFromObject, h as loadCookiesFromString, r as refreshAuthTokens } from './auth-BlG6x47F.js';
3
3
 
4
4
  /** Default directory for storing NotebookLM session files (~/.notebooklm). */
5
5
  declare const DEFAULT_SESSION_DIR: string;
package/dist/auth.js CHANGED
@@ -115,6 +115,12 @@ async function fetchTokens(cookies) {
115
115
  const sessionId = extractSessionId(html, finalUrl);
116
116
  return { csrfToken, sessionId };
117
117
  }
118
+ async function refreshAuthTokens(auth) {
119
+ const { csrfToken, sessionId } = await fetchTokens(auth.cookies);
120
+ auth.csrfToken = csrfToken;
121
+ auth.sessionId = sessionId;
122
+ return auth;
123
+ }
118
124
  function extractCsrfToken(html, finalUrl) {
119
125
  const match = /"SNlM0e"\s*:\s*"([^"]+)"/.exec(html);
120
126
  if (!match?.[1]) {
@@ -234,6 +240,6 @@ async function login(opts = {}) {
234
240
  };
235
241
  }
236
242
 
237
- export { DEFAULT_SESSION_DIR, DEFAULT_SESSION_FILE2 as DEFAULT_SESSION_FILE, buildCookieHeader, buildGoogleCookieHeader, connect, fetchTokens, loadCookiesFromFile, loadCookiesFromMap, loadCookiesFromObject, loadCookiesFromString, login };
243
+ export { DEFAULT_SESSION_DIR, DEFAULT_SESSION_FILE2 as DEFAULT_SESSION_FILE, buildCookieHeader, buildGoogleCookieHeader, connect, fetchTokens, loadCookiesFromFile, loadCookiesFromMap, loadCookiesFromObject, loadCookiesFromString, login, refreshAuthTokens };
238
244
  //# sourceMappingURL=auth.js.map
239
245
  //# sourceMappingURL=auth.js.map
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/errors.ts","../src/auth.ts","../src/auth/browser.ts"],"names":["join","homedir","DEFAULT_SESSION_FILE","NOTEBOOKLM_URL","existsSync"],"mappings":"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","file":"auth.js","sourcesContent":["/**\n * All exceptions for notebooklm-sdk.\n *\n * All errors extend NotebookLMError so you can catch everything with:\n * try { ... } catch (e) { if (e instanceof NotebookLMError) ... }\n */\n\nexport class NotebookLMError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Network (transport-level, before RPC processing)\n// ---------------------------------------------------------------------------\n\nexport class NetworkError extends NotebookLMError {\n readonly methodId?: string;\n readonly originalError?: Error;\n\n constructor(message: string, opts: { methodId?: string; originalError?: Error } = {}) {\n super(message);\n this.methodId = opts.methodId;\n this.originalError = opts.originalError;\n }\n}\n\nexport class RPCTimeoutError extends NetworkError {}\n\n// ---------------------------------------------------------------------------\n// RPC Protocol (after connection established)\n// ---------------------------------------------------------------------------\n\nexport class RPCError extends NotebookLMError {\n readonly methodId?: string;\n readonly rawResponse?: string;\n readonly rpcCode?: string | number;\n readonly foundIds: string[];\n\n constructor(\n message: string,\n opts: {\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message);\n this.methodId = opts.methodId;\n this.rawResponse = opts.rawResponse ? opts.rawResponse.slice(0, 500) : undefined;\n this.rpcCode = opts.rpcCode;\n this.foundIds = opts.foundIds ?? [];\n }\n}\n\nexport class AuthError extends RPCError {}\n\nexport class RateLimitError extends RPCError {\n readonly retryAfter?: number;\n\n constructor(\n message: string,\n opts: {\n retryAfter?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message, opts);\n this.retryAfter = opts.retryAfter;\n }\n}\n\nexport class ServerError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\nexport class ClientError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Notebooks\n// ---------------------------------------------------------------------------\n\nexport class NotebookError extends NotebookLMError {}\n\nexport class NotebookNotFoundError extends NotebookError {\n readonly notebookId: string;\n\n constructor(notebookId: string) {\n super(`Notebook not found: ${notebookId}`);\n this.notebookId = notebookId;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Sources\n// ---------------------------------------------------------------------------\n\nexport class SourceError extends NotebookLMError {}\n\nexport class SourceNotFoundError extends SourceError {\n readonly sourceId: string;\n\n constructor(sourceId: string) {\n super(`Source not found: ${sourceId}`);\n this.sourceId = sourceId;\n }\n}\n\nexport class SourceAddError extends SourceError {\n readonly url: string;\n readonly cause?: Error;\n\n constructor(url: string, opts: { cause?: Error; message?: string } = {}) {\n super(\n opts.message ??\n `Failed to add source: ${url}\\n` +\n \"Possible causes:\\n\" +\n \" - URL is invalid or inaccessible\\n\" +\n \" - Content is behind a paywall or requires authentication\\n\" +\n \" - Rate limiting or quota exceeded\",\n );\n this.url = url;\n this.cause = opts.cause;\n }\n}\n\nexport class SourceProcessingError extends SourceError {\n readonly sourceId: string;\n readonly status: number;\n\n constructor(sourceId: string, status = 3, message?: string) {\n super(message ?? `Source ${sourceId} failed to process`);\n this.sourceId = sourceId;\n this.status = status;\n }\n}\n\nexport class SourceTimeoutError extends SourceError {\n readonly sourceId: string;\n readonly timeout: number;\n readonly lastStatus?: number;\n\n constructor(sourceId: string, timeout: number, lastStatus?: number) {\n const statusInfo = lastStatus != null ? ` (last status: ${lastStatus})` : \"\";\n super(`Source ${sourceId} not ready after ${timeout.toFixed(1)}s${statusInfo}`);\n this.sourceId = sourceId;\n this.timeout = timeout;\n this.lastStatus = lastStatus;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Artifacts\n// ---------------------------------------------------------------------------\n\nexport class ArtifactError extends NotebookLMError {}\n\nexport class ArtifactNotFoundError extends ArtifactError {\n readonly artifactId: string;\n readonly artifactType?: string;\n\n constructor(artifactId: string, artifactType?: string) {\n const typeInfo = artifactType ? ` ${artifactType}` : \"\";\n super(`${typeInfo.trim() || \"Artifact\"} ${artifactId} not found`);\n this.artifactId = artifactId;\n this.artifactType = artifactType;\n }\n}\n\nexport class ArtifactNotReadyError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly status?: string;\n\n constructor(artifactType: string, opts: { artifactId?: string; status?: string } = {}) {\n const base = opts.artifactId\n ? `${artifactType} artifact ${opts.artifactId} is not ready`\n : `No completed ${artifactType} found`;\n const statusInfo = opts.status ? ` (status: ${opts.status})` : \"\";\n super(`${base}${statusInfo}`);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.status = opts.status;\n }\n}\n\nexport class ArtifactParseError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to parse ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\nexport class ArtifactDownloadError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to download ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Chat\n// ---------------------------------------------------------------------------\n\nexport class ChatError extends NotebookLMError {}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { AuthError } from \"./types/errors.js\";\n\n/** Default session file written by `npx notebooklm-sdk login`. */\nconst DEFAULT_SESSION_FILE = join(homedir(), \".notebooklm\", \"session.json\");\n\nexport interface CookieMap {\n [key: string]: string;\n}\n\nexport interface AuthTokens {\n cookies: CookieMap;\n csrfToken: string;\n sessionId: string;\n cookieHeader: string;\n /** Cookie header containing only .google.com domain cookies — for media downloads */\n googleCookieHeader: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cookie loading\n// ---------------------------------------------------------------------------\n\n/** Load cookies from a Playwright storage_state.json file. */\nexport function loadCookiesFromFile(filePath: string): CookieMap {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n throw new AuthError(`Session file not found: ${filePath}\\nRun: npx notebooklm-sdk login`);\n }\n return extractCookiesFromStorageState(JSON.parse(raw));\n}\n\n/** Load cookies from a raw Playwright storage state object. */\nexport function loadCookiesFromObject(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n return extractCookiesFromStorageState(storageState);\n}\n\n/** Build a cookie header containing only .google.com domain cookies (for media downloads). */\nexport function buildGoogleCookieHeader(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): string {\n const map: CookieMap = {};\n for (const c of storageState.cookies ?? []) {\n if (c.domain === \".google.com\" && c.name && c.value) {\n map[c.name] = map[c.name] ?? c.value;\n }\n }\n return buildCookieHeader(map);\n}\n\n/** Load cookies from a flat cookie map (already parsed). */\nexport function loadCookiesFromMap(map: CookieMap): CookieMap {\n return { ...map };\n}\n\n/** Load cookies from a \"; \"-separated cookie string (e.g. process.env.NOTEBOOKLM_COOKIES). */\nexport function loadCookiesFromString(cookieStr: string): CookieMap {\n const map: CookieMap = {};\n for (const part of cookieStr.split(/;\\s*/)) {\n const idx = part.indexOf(\"=\");\n if (idx > 0) {\n const name = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (name) map[name] = value;\n }\n }\n return map;\n}\n\nfunction extractCookiesFromStorageState(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n const cookies: CookieMap = {};\n const domainTrack: Record<string, string> = {};\n\n for (const cookie of storageState.cookies ?? []) {\n const { domain, name, value } = cookie;\n if (!isAllowedDomain(domain) || !name) continue;\n\n const isBase = domain === \".google.com\";\n if (!(name in cookies) || isBase) {\n cookies[name] = value;\n domainTrack[name] = domain;\n }\n }\n\n if (!cookies[\"SID\"]) {\n throw new AuthError(\n \"Missing required cookie: SID. Session may be invalid or expired.\\nRun: npx notebooklm-sdk login\",\n );\n }\n return cookies;\n}\n\nfunction isAllowedDomain(domain: string): boolean {\n if (\n domain === \".google.com\" ||\n domain === \"notebooklm.google.com\" ||\n domain === \".googleusercontent.com\"\n ) {\n return true;\n }\n if (domain.startsWith(\".google.\")) {\n return true; // Allow all regional Google domains\n }\n return false;\n}\n\nexport function buildCookieHeader(cookies: CookieMap): string {\n return Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \");\n}\n\n// ---------------------------------------------------------------------------\n// Token fetching\n// ---------------------------------------------------------------------------\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\n\nexport async function fetchTokens(\n cookies: CookieMap,\n): Promise<{ csrfToken: string; sessionId: string }> {\n const cookieHeader = buildCookieHeader(cookies);\n\n const response = await fetch(NOTEBOOKLM_URL, {\n headers: { Cookie: cookieHeader },\n redirect: \"follow\",\n });\n\n if (!response.ok) {\n throw new AuthError(`Failed to fetch NotebookLM page: HTTP ${response.status}`);\n }\n\n const finalUrl = response.url;\n if (isGoogleAuthRedirect(finalUrl)) {\n throw new AuthError(`Redirected to login page: ${finalUrl}. Cookies may be expired.`);\n }\n\n const html = await response.text();\n const csrfToken = extractCsrfToken(html, finalUrl);\n const sessionId = extractSessionId(html, finalUrl);\n\n return { csrfToken, sessionId };\n}\n\nfunction extractCsrfToken(html: string, finalUrl: string): string {\n const match = /\"SNlM0e\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"CSRF token (SNlM0e) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction extractSessionId(html: string, finalUrl: string): string {\n const match = /\"FdrFJe\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"Session ID (FdrFJe) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction isGoogleAuthRedirect(url: string): boolean {\n return url.includes(\"accounts.google.com\") || url.includes(\"signin\");\n}\n\n// ---------------------------------------------------------------------------\n// Connect options\n// ---------------------------------------------------------------------------\n\nexport interface ConnectOptions {\n /** \"; \"-separated cookie string (e.g. \"SID=abc; HSID=xyz\") */\n cookies?: string;\n /** Path to Playwright storage_state.json */\n cookiesFile?: string;\n /** Pre-parsed cookie map */\n cookiesObject?: CookieMap | { cookies?: Array<{ name: string; value: string; domain: string }> };\n}\n\nexport async function connect(opts: ConnectOptions = {}): Promise<AuthTokens> {\n let cookieMap: CookieMap;\n let googleCookieHeader: string | null = null;\n\n if (opts.cookies) {\n cookieMap = loadCookiesFromString(opts.cookies);\n } else if (opts.cookiesFile) {\n cookieMap = loadCookiesFromFile(opts.cookiesFile);\n } else if (opts.cookiesObject) {\n if (\"cookies\" in opts.cookiesObject && Array.isArray(opts.cookiesObject.cookies)) {\n const storageState = opts.cookiesObject as {\n cookies: Array<{ name: string; value: string; domain: string }>;\n };\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else {\n cookieMap = loadCookiesFromMap(opts.cookiesObject as CookieMap);\n }\n } else {\n // Auto-discovery: ~/.notebooklm/session.json → ./storage_state.json → env var\n const envCookies = process.env[\"NOTEBOOKLM_COOKIES\"];\n const envFile = process.env[\"NOTEBOOKLM_COOKIES_FILE\"];\n if (envFile) {\n cookieMap = loadCookiesFromFile(envFile);\n } else if (existsSync(DEFAULT_SESSION_FILE)) {\n const raw = readFileSync(DEFAULT_SESSION_FILE, \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (existsSync(\"storage_state.json\")) {\n const raw = readFileSync(\"storage_state.json\", \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (envCookies) {\n cookieMap = loadCookiesFromString(envCookies);\n } else {\n throw new AuthError(\"No session found. Run: npx notebooklm-sdk login\");\n }\n }\n\n const { csrfToken, sessionId } = await fetchTokens(cookieMap);\n const cookieHeader = buildCookieHeader(cookieMap);\n\n return {\n cookies: cookieMap,\n csrfToken,\n sessionId,\n cookieHeader,\n googleCookieHeader: googleCookieHeader ?? cookieHeader,\n };\n}\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type BrowserContext, chromium, type Page } from \"playwright\";\nimport { type CookieMap, loadCookiesFromObject } from \"../auth.js\";\n\n/** Default directory for storing NotebookLM session files (~/.notebooklm). */\nexport const DEFAULT_SESSION_DIR = join(homedir(), \".notebooklm\");\n/** Default session file path (~/.notebooklm/session.json). */\nexport const DEFAULT_SESSION_FILE = join(DEFAULT_SESSION_DIR, \"session.json\");\n\nexport interface LoginOptions {\n /**\n * Path to a directory for a persistent browser profile.\n * Defaults to ~/.notebooklm/.auth_profile.\n */\n persistFolder?: string;\n /**\n * Browser type to use. Default is \"chromium\".\n */\n browserType?: \"chromium\" | \"msedge\";\n /**\n * Whether to run the browser in headless mode. Default is false.\n * Headless login is usually blocked by Google, so this is mostly for testing or refreshes.\n */\n headless?: boolean;\n}\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\nconst GOOGLE_ACCOUNTS_URL = \"https://accounts.google.com/\";\n\n/**\n * Log in to NotebookLM via a headful browser window.\n *\n * Flow:\n * 1. Opens browser to NotebookLM.\n * 2. If already logged in (via persistFolder), it proceeds.\n * 3. If not, it waits for the user to reach the home page.\n * 4. Captures cookies and returns them.\n */\nexport async function login(opts: LoginOptions = {}): Promise<{\n cookies: CookieMap;\n storageState: any;\n cookieHeader: string;\n}> {\n const {\n persistFolder = join(DEFAULT_SESSION_DIR, \".auth_profile\"),\n headless = false,\n browserType = \"chromium\",\n } = opts;\n\n // Pre-flight: verify Playwright browser is installed\n try {\n chromium.executablePath();\n } catch {\n throw new Error(\"Playwright browser not found. Run: npx playwright install chromium\");\n }\n\n // Ensure the session directory exists\n if (!existsSync(DEFAULT_SESSION_DIR)) {\n mkdirSync(DEFAULT_SESSION_DIR, { recursive: true });\n }\n\n let context: BrowserContext;\n\n const launchOptions = {\n headless,\n args: [\"--disable-blink-features=AutomationControlled\"],\n };\n\n context = await chromium.launchPersistentContext(persistFolder, {\n ...launchOptions,\n channel: browserType === \"msedge\" ? \"msedge\" : undefined,\n });\n\n const page = context.pages()[0] || (await context.newPage());\n await page.goto(NOTEBOOKLM_URL);\n\n // Check if we are on the login page\n if (page.url().includes(\"accounts.google.com\")) {\n console.log(\"Please log in to Google in the browser window...\");\n\n // Wait for navigation back to NotebookLM or successful login indicator\n // We poll until the URL includes notebooklm.google.com and it's not a generic landing page\n await page.waitForURL(\n (url) => {\n return url.hostname === \"notebooklm.google.com\" && !url.pathname.includes(\"/login\");\n },\n { timeout: 0 },\n ); // No timeout, wait for user\n }\n\n // Ensure we are fully loaded on the accounts domain too to capture those cookies\n await page.goto(GOOGLE_ACCOUNTS_URL, { waitUntil: \"load\" });\n await page.goto(NOTEBOOKLM_URL, { waitUntil: \"load\" });\n\n const storageState = await context.storageState();\n const cookies = loadCookiesFromObject(storageState as any);\n\n await context.close();\n\n return {\n cookies,\n storageState,\n cookieHeader: Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \"),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/types/errors.ts","../src/auth.ts","../src/auth/browser.ts"],"names":["join","homedir","DEFAULT_SESSION_FILE","NOTEBOOKLM_URL","existsSync"],"mappings":"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","file":"auth.js","sourcesContent":["/**\n * All exceptions for notebooklm-sdk.\n *\n * All errors extend NotebookLMError so you can catch everything with:\n * try { ... } catch (e) { if (e instanceof NotebookLMError) ... }\n */\n\nexport class NotebookLMError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Network (transport-level, before RPC processing)\n// ---------------------------------------------------------------------------\n\nexport class NetworkError extends NotebookLMError {\n readonly methodId?: string;\n readonly originalError?: Error;\n\n constructor(message: string, opts: { methodId?: string; originalError?: Error } = {}) {\n super(message);\n this.methodId = opts.methodId;\n this.originalError = opts.originalError;\n }\n}\n\nexport class RPCTimeoutError extends NetworkError {}\n\n// ---------------------------------------------------------------------------\n// RPC Protocol (after connection established)\n// ---------------------------------------------------------------------------\n\nexport class RPCError extends NotebookLMError {\n readonly methodId?: string;\n readonly rawResponse?: string;\n readonly rpcCode?: string | number;\n readonly foundIds: string[];\n\n constructor(\n message: string,\n opts: {\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message);\n this.methodId = opts.methodId;\n this.rawResponse = opts.rawResponse ? opts.rawResponse.slice(0, 500) : undefined;\n this.rpcCode = opts.rpcCode;\n this.foundIds = opts.foundIds ?? [];\n }\n}\n\nexport class AuthError extends RPCError {}\n\nexport class RateLimitError extends RPCError {\n readonly retryAfter?: number;\n\n constructor(\n message: string,\n opts: {\n retryAfter?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message, opts);\n this.retryAfter = opts.retryAfter;\n }\n}\n\nexport class ServerError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\nexport class ClientError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Notebooks\n// ---------------------------------------------------------------------------\n\nexport class NotebookError extends NotebookLMError {}\n\nexport class NotebookNotFoundError extends NotebookError {\n readonly notebookId: string;\n\n constructor(notebookId: string) {\n super(`Notebook not found: ${notebookId}`);\n this.notebookId = notebookId;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Sources\n// ---------------------------------------------------------------------------\n\nexport class SourceError extends NotebookLMError {}\n\nexport class SourceNotFoundError extends SourceError {\n readonly sourceId: string;\n\n constructor(sourceId: string) {\n super(`Source not found: ${sourceId}`);\n this.sourceId = sourceId;\n }\n}\n\nexport class SourceAddError extends SourceError {\n readonly url: string;\n readonly cause?: Error;\n\n constructor(url: string, opts: { cause?: Error; message?: string } = {}) {\n super(\n opts.message ??\n `Failed to add source: ${url}\\n` +\n \"Possible causes:\\n\" +\n \" - URL is invalid or inaccessible\\n\" +\n \" - Content is behind a paywall or requires authentication\\n\" +\n \" - Rate limiting or quota exceeded\",\n );\n this.url = url;\n this.cause = opts.cause;\n }\n}\n\nexport class SourceProcessingError extends SourceError {\n readonly sourceId: string;\n readonly status: number;\n\n constructor(sourceId: string, status = 3, message?: string) {\n super(message ?? `Source ${sourceId} failed to process`);\n this.sourceId = sourceId;\n this.status = status;\n }\n}\n\nexport class SourceTimeoutError extends SourceError {\n readonly sourceId: string;\n readonly timeout: number;\n readonly lastStatus?: number;\n\n constructor(sourceId: string, timeout: number, lastStatus?: number) {\n const statusInfo = lastStatus != null ? ` (last status: ${lastStatus})` : \"\";\n super(`Source ${sourceId} not ready after ${timeout.toFixed(1)}s${statusInfo}`);\n this.sourceId = sourceId;\n this.timeout = timeout;\n this.lastStatus = lastStatus;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Artifacts\n// ---------------------------------------------------------------------------\n\nexport class ArtifactError extends NotebookLMError {}\n\nexport class ArtifactNotFoundError extends ArtifactError {\n readonly artifactId: string;\n readonly artifactType?: string;\n\n constructor(artifactId: string, artifactType?: string) {\n const typeInfo = artifactType ? ` ${artifactType}` : \"\";\n super(`${typeInfo.trim() || \"Artifact\"} ${artifactId} not found`);\n this.artifactId = artifactId;\n this.artifactType = artifactType;\n }\n}\n\nexport class ArtifactNotReadyError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly status?: string;\n\n constructor(artifactType: string, opts: { artifactId?: string; status?: string } = {}) {\n const base = opts.artifactId\n ? `${artifactType} artifact ${opts.artifactId} is not ready`\n : `No completed ${artifactType} found`;\n const statusInfo = opts.status ? ` (status: ${opts.status})` : \"\";\n super(`${base}${statusInfo}`);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.status = opts.status;\n }\n}\n\nexport class ArtifactParseError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to parse ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\nexport class ArtifactDownloadError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to download ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Chat\n// ---------------------------------------------------------------------------\n\nexport class ChatError extends NotebookLMError {}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { AuthError } from \"./types/errors.js\";\n\n/** Default session file written by `npx notebooklm-sdk login`. */\nconst DEFAULT_SESSION_FILE = join(homedir(), \".notebooklm\", \"session.json\");\n\nexport interface CookieMap {\n [key: string]: string;\n}\n\nexport interface AuthTokens {\n cookies: CookieMap;\n csrfToken: string;\n sessionId: string;\n cookieHeader: string;\n /** Cookie header containing only .google.com domain cookies — for media downloads */\n googleCookieHeader: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cookie loading\n// ---------------------------------------------------------------------------\n\n/** Load cookies from a Playwright storage_state.json file. */\nexport function loadCookiesFromFile(filePath: string): CookieMap {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n throw new AuthError(`Session file not found: ${filePath}\\nRun: npx notebooklm-sdk login`);\n }\n return extractCookiesFromStorageState(JSON.parse(raw));\n}\n\n/** Load cookies from a raw Playwright storage state object. */\nexport function loadCookiesFromObject(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n return extractCookiesFromStorageState(storageState);\n}\n\n/** Build a cookie header containing only .google.com domain cookies (for media downloads). */\nexport function buildGoogleCookieHeader(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): string {\n const map: CookieMap = {};\n for (const c of storageState.cookies ?? []) {\n if (c.domain === \".google.com\" && c.name && c.value) {\n map[c.name] = map[c.name] ?? c.value;\n }\n }\n return buildCookieHeader(map);\n}\n\n/** Load cookies from a flat cookie map (already parsed). */\nexport function loadCookiesFromMap(map: CookieMap): CookieMap {\n return { ...map };\n}\n\n/** Load cookies from a \"; \"-separated cookie string (e.g. process.env.NOTEBOOKLM_COOKIES). */\nexport function loadCookiesFromString(cookieStr: string): CookieMap {\n const map: CookieMap = {};\n for (const part of cookieStr.split(/;\\s*/)) {\n const idx = part.indexOf(\"=\");\n if (idx > 0) {\n const name = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (name) map[name] = value;\n }\n }\n return map;\n}\n\nfunction extractCookiesFromStorageState(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n const cookies: CookieMap = {};\n const domainTrack: Record<string, string> = {};\n\n for (const cookie of storageState.cookies ?? []) {\n const { domain, name, value } = cookie;\n if (!isAllowedDomain(domain) || !name) continue;\n\n const isBase = domain === \".google.com\";\n if (!(name in cookies) || isBase) {\n cookies[name] = value;\n domainTrack[name] = domain;\n }\n }\n\n if (!cookies[\"SID\"]) {\n throw new AuthError(\n \"Missing required cookie: SID. Session may be invalid or expired.\\nRun: npx notebooklm-sdk login\",\n );\n }\n return cookies;\n}\n\nfunction isAllowedDomain(domain: string): boolean {\n if (\n domain === \".google.com\" ||\n domain === \"notebooklm.google.com\" ||\n domain === \".googleusercontent.com\"\n ) {\n return true;\n }\n if (domain.startsWith(\".google.\")) {\n return true; // Allow all regional Google domains\n }\n return false;\n}\n\nexport function buildCookieHeader(cookies: CookieMap): string {\n return Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \");\n}\n\n// ---------------------------------------------------------------------------\n// Token fetching\n// ---------------------------------------------------------------------------\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\n\nexport async function fetchTokens(\n cookies: CookieMap,\n): Promise<{ csrfToken: string; sessionId: string }> {\n const cookieHeader = buildCookieHeader(cookies);\n\n const response = await fetch(NOTEBOOKLM_URL, {\n headers: { Cookie: cookieHeader },\n redirect: \"follow\",\n });\n\n if (!response.ok) {\n throw new AuthError(`Failed to fetch NotebookLM page: HTTP ${response.status}`);\n }\n\n const finalUrl = response.url;\n if (isGoogleAuthRedirect(finalUrl)) {\n throw new AuthError(`Redirected to login page: ${finalUrl}. Cookies may be expired.`);\n }\n\n const html = await response.text();\n const csrfToken = extractCsrfToken(html, finalUrl);\n const sessionId = extractSessionId(html, finalUrl);\n\n return { csrfToken, sessionId };\n}\n\nexport async function refreshAuthTokens(auth: AuthTokens): Promise<AuthTokens> {\n const { csrfToken, sessionId } = await fetchTokens(auth.cookies);\n auth.csrfToken = csrfToken;\n auth.sessionId = sessionId;\n return auth;\n}\n\nfunction extractCsrfToken(html: string, finalUrl: string): string {\n const match = /\"SNlM0e\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"CSRF token (SNlM0e) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction extractSessionId(html: string, finalUrl: string): string {\n const match = /\"FdrFJe\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"Session ID (FdrFJe) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction isGoogleAuthRedirect(url: string): boolean {\n return url.includes(\"accounts.google.com\") || url.includes(\"signin\");\n}\n\n// ---------------------------------------------------------------------------\n// Connect options\n// ---------------------------------------------------------------------------\n\nexport interface ConnectOptions {\n /** \"; \"-separated cookie string (e.g. \"SID=abc; HSID=xyz\") */\n cookies?: string;\n /** Path to Playwright storage_state.json */\n cookiesFile?: string;\n /** Pre-parsed cookie map */\n cookiesObject?: CookieMap | { cookies?: Array<{ name: string; value: string; domain: string }> };\n}\n\nexport async function connect(opts: ConnectOptions = {}): Promise<AuthTokens> {\n let cookieMap: CookieMap;\n let googleCookieHeader: string | null = null;\n\n if (opts.cookies) {\n cookieMap = loadCookiesFromString(opts.cookies);\n } else if (opts.cookiesFile) {\n cookieMap = loadCookiesFromFile(opts.cookiesFile);\n } else if (opts.cookiesObject) {\n if (\"cookies\" in opts.cookiesObject && Array.isArray(opts.cookiesObject.cookies)) {\n const storageState = opts.cookiesObject as {\n cookies: Array<{ name: string; value: string; domain: string }>;\n };\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else {\n cookieMap = loadCookiesFromMap(opts.cookiesObject as CookieMap);\n }\n } else {\n // Auto-discovery: ~/.notebooklm/session.json → ./storage_state.json → env var\n const envCookies = process.env[\"NOTEBOOKLM_COOKIES\"];\n const envFile = process.env[\"NOTEBOOKLM_COOKIES_FILE\"];\n if (envFile) {\n cookieMap = loadCookiesFromFile(envFile);\n } else if (existsSync(DEFAULT_SESSION_FILE)) {\n const raw = readFileSync(DEFAULT_SESSION_FILE, \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (existsSync(\"storage_state.json\")) {\n const raw = readFileSync(\"storage_state.json\", \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (envCookies) {\n cookieMap = loadCookiesFromString(envCookies);\n } else {\n throw new AuthError(\"No session found. Run: npx notebooklm-sdk login\");\n }\n }\n\n const { csrfToken, sessionId } = await fetchTokens(cookieMap);\n const cookieHeader = buildCookieHeader(cookieMap);\n\n return {\n cookies: cookieMap,\n csrfToken,\n sessionId,\n cookieHeader,\n googleCookieHeader: googleCookieHeader ?? cookieHeader,\n };\n}\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type BrowserContext, chromium, type Page } from \"playwright\";\nimport { type CookieMap, loadCookiesFromObject } from \"../auth.js\";\n\n/** Default directory for storing NotebookLM session files (~/.notebooklm). */\nexport const DEFAULT_SESSION_DIR = join(homedir(), \".notebooklm\");\n/** Default session file path (~/.notebooklm/session.json). */\nexport const DEFAULT_SESSION_FILE = join(DEFAULT_SESSION_DIR, \"session.json\");\n\nexport interface LoginOptions {\n /**\n * Path to a directory for a persistent browser profile.\n * Defaults to ~/.notebooklm/.auth_profile.\n */\n persistFolder?: string;\n /**\n * Browser type to use. Default is \"chromium\".\n */\n browserType?: \"chromium\" | \"msedge\";\n /**\n * Whether to run the browser in headless mode. Default is false.\n * Headless login is usually blocked by Google, so this is mostly for testing or refreshes.\n */\n headless?: boolean;\n}\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\nconst GOOGLE_ACCOUNTS_URL = \"https://accounts.google.com/\";\n\n/**\n * Log in to NotebookLM via a headful browser window.\n *\n * Flow:\n * 1. Opens browser to NotebookLM.\n * 2. If already logged in (via persistFolder), it proceeds.\n * 3. If not, it waits for the user to reach the home page.\n * 4. Captures cookies and returns them.\n */\nexport async function login(opts: LoginOptions = {}): Promise<{\n cookies: CookieMap;\n storageState: any;\n cookieHeader: string;\n}> {\n const {\n persistFolder = join(DEFAULT_SESSION_DIR, \".auth_profile\"),\n headless = false,\n browserType = \"chromium\",\n } = opts;\n\n // Pre-flight: verify Playwright browser is installed\n try {\n chromium.executablePath();\n } catch {\n throw new Error(\"Playwright browser not found. Run: npx playwright install chromium\");\n }\n\n // Ensure the session directory exists\n if (!existsSync(DEFAULT_SESSION_DIR)) {\n mkdirSync(DEFAULT_SESSION_DIR, { recursive: true });\n }\n\n let context: BrowserContext;\n\n const launchOptions = {\n headless,\n args: [\"--disable-blink-features=AutomationControlled\"],\n };\n\n context = await chromium.launchPersistentContext(persistFolder, {\n ...launchOptions,\n channel: browserType === \"msedge\" ? \"msedge\" : undefined,\n });\n\n const page = context.pages()[0] || (await context.newPage());\n await page.goto(NOTEBOOKLM_URL);\n\n // Check if we are on the login page\n if (page.url().includes(\"accounts.google.com\")) {\n console.log(\"Please log in to Google in the browser window...\");\n\n // Wait for navigation back to NotebookLM or successful login indicator\n // We poll until the URL includes notebooklm.google.com and it's not a generic landing page\n await page.waitForURL(\n (url) => {\n return url.hostname === \"notebooklm.google.com\" && !url.pathname.includes(\"/login\");\n },\n { timeout: 0 },\n ); // No timeout, wait for user\n }\n\n // Ensure we are fully loaded on the accounts domain too to capture those cookies\n await page.goto(GOOGLE_ACCOUNTS_URL, { waitUntil: \"load\" });\n await page.goto(NOTEBOOKLM_URL, { waitUntil: \"load\" });\n\n const storageState = await context.storageState();\n const cookies = loadCookiesFromObject(storageState as any);\n\n await context.close();\n\n return {\n cookies,\n storageState,\n cookieHeader: Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \"),\n };\n}\n"]}
package/dist/bin.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/errors.ts","../src/auth.ts","../src/auth/browser.ts","../src/bin.ts"],"names":["join","homedir","readFileSync","existsSync","DEFAULT_SESSION_FILE","NOTEBOOKLM_URL","chromium","mkdirSync","writeFileSync"],"mappings":"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","file":"bin.cjs","sourcesContent":["/**\n * All exceptions for notebooklm-sdk.\n *\n * All errors extend NotebookLMError so you can catch everything with:\n * try { ... } catch (e) { if (e instanceof NotebookLMError) ... }\n */\n\nexport class NotebookLMError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Network (transport-level, before RPC processing)\n// ---------------------------------------------------------------------------\n\nexport class NetworkError extends NotebookLMError {\n readonly methodId?: string;\n readonly originalError?: Error;\n\n constructor(message: string, opts: { methodId?: string; originalError?: Error } = {}) {\n super(message);\n this.methodId = opts.methodId;\n this.originalError = opts.originalError;\n }\n}\n\nexport class RPCTimeoutError extends NetworkError {}\n\n// ---------------------------------------------------------------------------\n// RPC Protocol (after connection established)\n// ---------------------------------------------------------------------------\n\nexport class RPCError extends NotebookLMError {\n readonly methodId?: string;\n readonly rawResponse?: string;\n readonly rpcCode?: string | number;\n readonly foundIds: string[];\n\n constructor(\n message: string,\n opts: {\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message);\n this.methodId = opts.methodId;\n this.rawResponse = opts.rawResponse ? opts.rawResponse.slice(0, 500) : undefined;\n this.rpcCode = opts.rpcCode;\n this.foundIds = opts.foundIds ?? [];\n }\n}\n\nexport class AuthError extends RPCError {}\n\nexport class RateLimitError extends RPCError {\n readonly retryAfter?: number;\n\n constructor(\n message: string,\n opts: {\n retryAfter?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message, opts);\n this.retryAfter = opts.retryAfter;\n }\n}\n\nexport class ServerError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\nexport class ClientError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Notebooks\n// ---------------------------------------------------------------------------\n\nexport class NotebookError extends NotebookLMError {}\n\nexport class NotebookNotFoundError extends NotebookError {\n readonly notebookId: string;\n\n constructor(notebookId: string) {\n super(`Notebook not found: ${notebookId}`);\n this.notebookId = notebookId;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Sources\n// ---------------------------------------------------------------------------\n\nexport class SourceError extends NotebookLMError {}\n\nexport class SourceNotFoundError extends SourceError {\n readonly sourceId: string;\n\n constructor(sourceId: string) {\n super(`Source not found: ${sourceId}`);\n this.sourceId = sourceId;\n }\n}\n\nexport class SourceAddError extends SourceError {\n readonly url: string;\n readonly cause?: Error;\n\n constructor(url: string, opts: { cause?: Error; message?: string } = {}) {\n super(\n opts.message ??\n `Failed to add source: ${url}\\n` +\n \"Possible causes:\\n\" +\n \" - URL is invalid or inaccessible\\n\" +\n \" - Content is behind a paywall or requires authentication\\n\" +\n \" - Rate limiting or quota exceeded\",\n );\n this.url = url;\n this.cause = opts.cause;\n }\n}\n\nexport class SourceProcessingError extends SourceError {\n readonly sourceId: string;\n readonly status: number;\n\n constructor(sourceId: string, status = 3, message?: string) {\n super(message ?? `Source ${sourceId} failed to process`);\n this.sourceId = sourceId;\n this.status = status;\n }\n}\n\nexport class SourceTimeoutError extends SourceError {\n readonly sourceId: string;\n readonly timeout: number;\n readonly lastStatus?: number;\n\n constructor(sourceId: string, timeout: number, lastStatus?: number) {\n const statusInfo = lastStatus != null ? ` (last status: ${lastStatus})` : \"\";\n super(`Source ${sourceId} not ready after ${timeout.toFixed(1)}s${statusInfo}`);\n this.sourceId = sourceId;\n this.timeout = timeout;\n this.lastStatus = lastStatus;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Artifacts\n// ---------------------------------------------------------------------------\n\nexport class ArtifactError extends NotebookLMError {}\n\nexport class ArtifactNotFoundError extends ArtifactError {\n readonly artifactId: string;\n readonly artifactType?: string;\n\n constructor(artifactId: string, artifactType?: string) {\n const typeInfo = artifactType ? ` ${artifactType}` : \"\";\n super(`${typeInfo.trim() || \"Artifact\"} ${artifactId} not found`);\n this.artifactId = artifactId;\n this.artifactType = artifactType;\n }\n}\n\nexport class ArtifactNotReadyError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly status?: string;\n\n constructor(artifactType: string, opts: { artifactId?: string; status?: string } = {}) {\n const base = opts.artifactId\n ? `${artifactType} artifact ${opts.artifactId} is not ready`\n : `No completed ${artifactType} found`;\n const statusInfo = opts.status ? ` (status: ${opts.status})` : \"\";\n super(`${base}${statusInfo}`);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.status = opts.status;\n }\n}\n\nexport class ArtifactParseError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to parse ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\nexport class ArtifactDownloadError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to download ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Chat\n// ---------------------------------------------------------------------------\n\nexport class ChatError extends NotebookLMError {}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { AuthError } from \"./types/errors.js\";\n\n/** Default session file written by `npx notebooklm-sdk login`. */\nconst DEFAULT_SESSION_FILE = join(homedir(), \".notebooklm\", \"session.json\");\n\nexport interface CookieMap {\n [key: string]: string;\n}\n\nexport interface AuthTokens {\n cookies: CookieMap;\n csrfToken: string;\n sessionId: string;\n cookieHeader: string;\n /** Cookie header containing only .google.com domain cookies — for media downloads */\n googleCookieHeader: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cookie loading\n// ---------------------------------------------------------------------------\n\n/** Load cookies from a Playwright storage_state.json file. */\nexport function loadCookiesFromFile(filePath: string): CookieMap {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n throw new AuthError(`Session file not found: ${filePath}\\nRun: npx notebooklm-sdk login`);\n }\n return extractCookiesFromStorageState(JSON.parse(raw));\n}\n\n/** Load cookies from a raw Playwright storage state object. */\nexport function loadCookiesFromObject(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n return extractCookiesFromStorageState(storageState);\n}\n\n/** Build a cookie header containing only .google.com domain cookies (for media downloads). */\nexport function buildGoogleCookieHeader(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): string {\n const map: CookieMap = {};\n for (const c of storageState.cookies ?? []) {\n if (c.domain === \".google.com\" && c.name && c.value) {\n map[c.name] = map[c.name] ?? c.value;\n }\n }\n return buildCookieHeader(map);\n}\n\n/** Load cookies from a flat cookie map (already parsed). */\nexport function loadCookiesFromMap(map: CookieMap): CookieMap {\n return { ...map };\n}\n\n/** Load cookies from a \"; \"-separated cookie string (e.g. process.env.NOTEBOOKLM_COOKIES). */\nexport function loadCookiesFromString(cookieStr: string): CookieMap {\n const map: CookieMap = {};\n for (const part of cookieStr.split(/;\\s*/)) {\n const idx = part.indexOf(\"=\");\n if (idx > 0) {\n const name = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (name) map[name] = value;\n }\n }\n return map;\n}\n\nfunction extractCookiesFromStorageState(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n const cookies: CookieMap = {};\n const domainTrack: Record<string, string> = {};\n\n for (const cookie of storageState.cookies ?? []) {\n const { domain, name, value } = cookie;\n if (!isAllowedDomain(domain) || !name) continue;\n\n const isBase = domain === \".google.com\";\n if (!(name in cookies) || isBase) {\n cookies[name] = value;\n domainTrack[name] = domain;\n }\n }\n\n if (!cookies[\"SID\"]) {\n throw new AuthError(\n \"Missing required cookie: SID. Session may be invalid or expired.\\nRun: npx notebooklm-sdk login\",\n );\n }\n return cookies;\n}\n\nfunction isAllowedDomain(domain: string): boolean {\n if (\n domain === \".google.com\" ||\n domain === \"notebooklm.google.com\" ||\n domain === \".googleusercontent.com\"\n ) {\n return true;\n }\n if (domain.startsWith(\".google.\")) {\n return true; // Allow all regional Google domains\n }\n return false;\n}\n\nexport function buildCookieHeader(cookies: CookieMap): string {\n return Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \");\n}\n\n// ---------------------------------------------------------------------------\n// Token fetching\n// ---------------------------------------------------------------------------\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\n\nexport async function fetchTokens(\n cookies: CookieMap,\n): Promise<{ csrfToken: string; sessionId: string }> {\n const cookieHeader = buildCookieHeader(cookies);\n\n const response = await fetch(NOTEBOOKLM_URL, {\n headers: { Cookie: cookieHeader },\n redirect: \"follow\",\n });\n\n if (!response.ok) {\n throw new AuthError(`Failed to fetch NotebookLM page: HTTP ${response.status}`);\n }\n\n const finalUrl = response.url;\n if (isGoogleAuthRedirect(finalUrl)) {\n throw new AuthError(`Redirected to login page: ${finalUrl}. Cookies may be expired.`);\n }\n\n const html = await response.text();\n const csrfToken = extractCsrfToken(html, finalUrl);\n const sessionId = extractSessionId(html, finalUrl);\n\n return { csrfToken, sessionId };\n}\n\nfunction extractCsrfToken(html: string, finalUrl: string): string {\n const match = /\"SNlM0e\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"CSRF token (SNlM0e) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction extractSessionId(html: string, finalUrl: string): string {\n const match = /\"FdrFJe\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"Session ID (FdrFJe) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction isGoogleAuthRedirect(url: string): boolean {\n return url.includes(\"accounts.google.com\") || url.includes(\"signin\");\n}\n\n// ---------------------------------------------------------------------------\n// Connect options\n// ---------------------------------------------------------------------------\n\nexport interface ConnectOptions {\n /** \"; \"-separated cookie string (e.g. \"SID=abc; HSID=xyz\") */\n cookies?: string;\n /** Path to Playwright storage_state.json */\n cookiesFile?: string;\n /** Pre-parsed cookie map */\n cookiesObject?: CookieMap | { cookies?: Array<{ name: string; value: string; domain: string }> };\n}\n\nexport async function connect(opts: ConnectOptions = {}): Promise<AuthTokens> {\n let cookieMap: CookieMap;\n let googleCookieHeader: string | null = null;\n\n if (opts.cookies) {\n cookieMap = loadCookiesFromString(opts.cookies);\n } else if (opts.cookiesFile) {\n cookieMap = loadCookiesFromFile(opts.cookiesFile);\n } else if (opts.cookiesObject) {\n if (\"cookies\" in opts.cookiesObject && Array.isArray(opts.cookiesObject.cookies)) {\n const storageState = opts.cookiesObject as {\n cookies: Array<{ name: string; value: string; domain: string }>;\n };\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else {\n cookieMap = loadCookiesFromMap(opts.cookiesObject as CookieMap);\n }\n } else {\n // Auto-discovery: ~/.notebooklm/session.json → ./storage_state.json → env var\n const envCookies = process.env[\"NOTEBOOKLM_COOKIES\"];\n const envFile = process.env[\"NOTEBOOKLM_COOKIES_FILE\"];\n if (envFile) {\n cookieMap = loadCookiesFromFile(envFile);\n } else if (existsSync(DEFAULT_SESSION_FILE)) {\n const raw = readFileSync(DEFAULT_SESSION_FILE, \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (existsSync(\"storage_state.json\")) {\n const raw = readFileSync(\"storage_state.json\", \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (envCookies) {\n cookieMap = loadCookiesFromString(envCookies);\n } else {\n throw new AuthError(\"No session found. Run: npx notebooklm-sdk login\");\n }\n }\n\n const { csrfToken, sessionId } = await fetchTokens(cookieMap);\n const cookieHeader = buildCookieHeader(cookieMap);\n\n return {\n cookies: cookieMap,\n csrfToken,\n sessionId,\n cookieHeader,\n googleCookieHeader: googleCookieHeader ?? cookieHeader,\n };\n}\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type BrowserContext, chromium, type Page } from \"playwright\";\nimport { type CookieMap, loadCookiesFromObject } from \"../auth.js\";\n\n/** Default directory for storing NotebookLM session files (~/.notebooklm). */\nexport const DEFAULT_SESSION_DIR = join(homedir(), \".notebooklm\");\n/** Default session file path (~/.notebooklm/session.json). */\nexport const DEFAULT_SESSION_FILE = join(DEFAULT_SESSION_DIR, \"session.json\");\n\nexport interface LoginOptions {\n /**\n * Path to a directory for a persistent browser profile.\n * Defaults to ~/.notebooklm/.auth_profile.\n */\n persistFolder?: string;\n /**\n * Browser type to use. Default is \"chromium\".\n */\n browserType?: \"chromium\" | \"msedge\";\n /**\n * Whether to run the browser in headless mode. Default is false.\n * Headless login is usually blocked by Google, so this is mostly for testing or refreshes.\n */\n headless?: boolean;\n}\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\nconst GOOGLE_ACCOUNTS_URL = \"https://accounts.google.com/\";\n\n/**\n * Log in to NotebookLM via a headful browser window.\n *\n * Flow:\n * 1. Opens browser to NotebookLM.\n * 2. If already logged in (via persistFolder), it proceeds.\n * 3. If not, it waits for the user to reach the home page.\n * 4. Captures cookies and returns them.\n */\nexport async function login(opts: LoginOptions = {}): Promise<{\n cookies: CookieMap;\n storageState: any;\n cookieHeader: string;\n}> {\n const {\n persistFolder = join(DEFAULT_SESSION_DIR, \".auth_profile\"),\n headless = false,\n browserType = \"chromium\",\n } = opts;\n\n // Pre-flight: verify Playwright browser is installed\n try {\n chromium.executablePath();\n } catch {\n throw new Error(\"Playwright browser not found. Run: npx playwright install chromium\");\n }\n\n // Ensure the session directory exists\n if (!existsSync(DEFAULT_SESSION_DIR)) {\n mkdirSync(DEFAULT_SESSION_DIR, { recursive: true });\n }\n\n let context: BrowserContext;\n\n const launchOptions = {\n headless,\n args: [\"--disable-blink-features=AutomationControlled\"],\n };\n\n context = await chromium.launchPersistentContext(persistFolder, {\n ...launchOptions,\n channel: browserType === \"msedge\" ? \"msedge\" : undefined,\n });\n\n const page = context.pages()[0] || (await context.newPage());\n await page.goto(NOTEBOOKLM_URL);\n\n // Check if we are on the login page\n if (page.url().includes(\"accounts.google.com\")) {\n console.log(\"Please log in to Google in the browser window...\");\n\n // Wait for navigation back to NotebookLM or successful login indicator\n // We poll until the URL includes notebooklm.google.com and it's not a generic landing page\n await page.waitForURL(\n (url) => {\n return url.hostname === \"notebooklm.google.com\" && !url.pathname.includes(\"/login\");\n },\n { timeout: 0 },\n ); // No timeout, wait for user\n }\n\n // Ensure we are fully loaded on the accounts domain too to capture those cookies\n await page.goto(GOOGLE_ACCOUNTS_URL, { waitUntil: \"load\" });\n await page.goto(NOTEBOOKLM_URL, { waitUntil: \"load\" });\n\n const storageState = await context.storageState();\n const cookies = loadCookiesFromObject(storageState as any);\n\n await context.close();\n\n return {\n cookies,\n storageState,\n cookieHeader: Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \"),\n };\n}\n","#!/usr/bin/env node\nimport { writeFileSync } from \"node:fs\";\nimport { DEFAULT_SESSION_DIR, DEFAULT_SESSION_FILE, login } from \"./auth/browser.js\";\nimport { connect } from \"./auth.js\";\n\nasync function run() {\n const args = process.argv.slice(2);\n const command = args[0];\n\n if (command === \"login\") {\n console.log(\"Starting browser login flow...\");\n console.log(\"A browser window will open. Please log in to your Google account.\");\n\n try {\n const authResult = await login();\n\n writeFileSync(DEFAULT_SESSION_FILE, JSON.stringify(authResult.storageState, null, 2));\n\n console.log(\"\\nLogin successful!\");\n console.log(`Session saved to: ${DEFAULT_SESSION_FILE}`);\n console.log(\"\\nIn your code:\");\n console.log(\" const client = await NotebookLMClient.connect();\");\n } catch (error) {\n console.error(\"Login failed:\", error instanceof Error ? error.message : error);\n process.exit(1);\n }\n } else if (command === \"whoami\") {\n try {\n const auth = await connect();\n console.log(\"Session valid\");\n console.log(`Session file: ${DEFAULT_SESSION_FILE}`);\n console.log(`CSRF token: ${auth.csrfToken.slice(0, 8)}...`);\n } catch (error) {\n console.error(\"Not authenticated:\", error instanceof Error ? error.message : error);\n process.exit(1);\n }\n } else {\n console.log(\"NotebookLM SDK CLI\");\n console.log(\"\\nUsage:\");\n console.log(\" npx notebooklm-sdk login Authenticate via browser\");\n console.log(\" npx notebooklm-sdk whoami Check current session\");\n process.exit(command ? 1 : 0);\n }\n}\n\nrun();\n"]}
1
+ {"version":3,"sources":["../src/types/errors.ts","../src/auth.ts","../src/auth/browser.ts","../src/bin.ts"],"names":["join","homedir","readFileSync","existsSync","DEFAULT_SESSION_FILE","NOTEBOOKLM_URL","chromium","mkdirSync","writeFileSync"],"mappings":"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","file":"bin.cjs","sourcesContent":["/**\n * All exceptions for notebooklm-sdk.\n *\n * All errors extend NotebookLMError so you can catch everything with:\n * try { ... } catch (e) { if (e instanceof NotebookLMError) ... }\n */\n\nexport class NotebookLMError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Network (transport-level, before RPC processing)\n// ---------------------------------------------------------------------------\n\nexport class NetworkError extends NotebookLMError {\n readonly methodId?: string;\n readonly originalError?: Error;\n\n constructor(message: string, opts: { methodId?: string; originalError?: Error } = {}) {\n super(message);\n this.methodId = opts.methodId;\n this.originalError = opts.originalError;\n }\n}\n\nexport class RPCTimeoutError extends NetworkError {}\n\n// ---------------------------------------------------------------------------\n// RPC Protocol (after connection established)\n// ---------------------------------------------------------------------------\n\nexport class RPCError extends NotebookLMError {\n readonly methodId?: string;\n readonly rawResponse?: string;\n readonly rpcCode?: string | number;\n readonly foundIds: string[];\n\n constructor(\n message: string,\n opts: {\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message);\n this.methodId = opts.methodId;\n this.rawResponse = opts.rawResponse ? opts.rawResponse.slice(0, 500) : undefined;\n this.rpcCode = opts.rpcCode;\n this.foundIds = opts.foundIds ?? [];\n }\n}\n\nexport class AuthError extends RPCError {}\n\nexport class RateLimitError extends RPCError {\n readonly retryAfter?: number;\n\n constructor(\n message: string,\n opts: {\n retryAfter?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n foundIds?: string[];\n } = {},\n ) {\n super(message, opts);\n this.retryAfter = opts.retryAfter;\n }\n}\n\nexport class ServerError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\nexport class ClientError extends RPCError {\n readonly statusCode?: number;\n\n constructor(\n message: string,\n opts: {\n statusCode?: number;\n methodId?: string;\n rawResponse?: string;\n rpcCode?: string | number;\n } = {},\n ) {\n super(message, opts);\n this.statusCode = opts.statusCode;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Notebooks\n// ---------------------------------------------------------------------------\n\nexport class NotebookError extends NotebookLMError {}\n\nexport class NotebookNotFoundError extends NotebookError {\n readonly notebookId: string;\n\n constructor(notebookId: string) {\n super(`Notebook not found: ${notebookId}`);\n this.notebookId = notebookId;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Sources\n// ---------------------------------------------------------------------------\n\nexport class SourceError extends NotebookLMError {}\n\nexport class SourceNotFoundError extends SourceError {\n readonly sourceId: string;\n\n constructor(sourceId: string) {\n super(`Source not found: ${sourceId}`);\n this.sourceId = sourceId;\n }\n}\n\nexport class SourceAddError extends SourceError {\n readonly url: string;\n readonly cause?: Error;\n\n constructor(url: string, opts: { cause?: Error; message?: string } = {}) {\n super(\n opts.message ??\n `Failed to add source: ${url}\\n` +\n \"Possible causes:\\n\" +\n \" - URL is invalid or inaccessible\\n\" +\n \" - Content is behind a paywall or requires authentication\\n\" +\n \" - Rate limiting or quota exceeded\",\n );\n this.url = url;\n this.cause = opts.cause;\n }\n}\n\nexport class SourceProcessingError extends SourceError {\n readonly sourceId: string;\n readonly status: number;\n\n constructor(sourceId: string, status = 3, message?: string) {\n super(message ?? `Source ${sourceId} failed to process`);\n this.sourceId = sourceId;\n this.status = status;\n }\n}\n\nexport class SourceTimeoutError extends SourceError {\n readonly sourceId: string;\n readonly timeout: number;\n readonly lastStatus?: number;\n\n constructor(sourceId: string, timeout: number, lastStatus?: number) {\n const statusInfo = lastStatus != null ? ` (last status: ${lastStatus})` : \"\";\n super(`Source ${sourceId} not ready after ${timeout.toFixed(1)}s${statusInfo}`);\n this.sourceId = sourceId;\n this.timeout = timeout;\n this.lastStatus = lastStatus;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Artifacts\n// ---------------------------------------------------------------------------\n\nexport class ArtifactError extends NotebookLMError {}\n\nexport class ArtifactNotFoundError extends ArtifactError {\n readonly artifactId: string;\n readonly artifactType?: string;\n\n constructor(artifactId: string, artifactType?: string) {\n const typeInfo = artifactType ? ` ${artifactType}` : \"\";\n super(`${typeInfo.trim() || \"Artifact\"} ${artifactId} not found`);\n this.artifactId = artifactId;\n this.artifactType = artifactType;\n }\n}\n\nexport class ArtifactNotReadyError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly status?: string;\n\n constructor(artifactType: string, opts: { artifactId?: string; status?: string } = {}) {\n const base = opts.artifactId\n ? `${artifactType} artifact ${opts.artifactId} is not ready`\n : `No completed ${artifactType} found`;\n const statusInfo = opts.status ? ` (status: ${opts.status})` : \"\";\n super(`${base}${statusInfo}`);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.status = opts.status;\n }\n}\n\nexport class ArtifactParseError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to parse ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\nexport class ArtifactDownloadError extends ArtifactError {\n readonly artifactType: string;\n readonly artifactId?: string;\n readonly details?: string;\n readonly cause?: Error;\n\n constructor(\n artifactType: string,\n opts: { details?: string; artifactId?: string; cause?: Error } = {},\n ) {\n let msg = `Failed to download ${artifactType} artifact`;\n if (opts.artifactId) msg += ` ${opts.artifactId}`;\n if (opts.details) msg += `: ${opts.details}`;\n super(msg);\n this.artifactType = artifactType;\n this.artifactId = opts.artifactId;\n this.details = opts.details;\n this.cause = opts.cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Domain: Chat\n// ---------------------------------------------------------------------------\n\nexport class ChatError extends NotebookLMError {}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { AuthError } from \"./types/errors.js\";\n\n/** Default session file written by `npx notebooklm-sdk login`. */\nconst DEFAULT_SESSION_FILE = join(homedir(), \".notebooklm\", \"session.json\");\n\nexport interface CookieMap {\n [key: string]: string;\n}\n\nexport interface AuthTokens {\n cookies: CookieMap;\n csrfToken: string;\n sessionId: string;\n cookieHeader: string;\n /** Cookie header containing only .google.com domain cookies — for media downloads */\n googleCookieHeader: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cookie loading\n// ---------------------------------------------------------------------------\n\n/** Load cookies from a Playwright storage_state.json file. */\nexport function loadCookiesFromFile(filePath: string): CookieMap {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n throw new AuthError(`Session file not found: ${filePath}\\nRun: npx notebooklm-sdk login`);\n }\n return extractCookiesFromStorageState(JSON.parse(raw));\n}\n\n/** Load cookies from a raw Playwright storage state object. */\nexport function loadCookiesFromObject(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n return extractCookiesFromStorageState(storageState);\n}\n\n/** Build a cookie header containing only .google.com domain cookies (for media downloads). */\nexport function buildGoogleCookieHeader(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): string {\n const map: CookieMap = {};\n for (const c of storageState.cookies ?? []) {\n if (c.domain === \".google.com\" && c.name && c.value) {\n map[c.name] = map[c.name] ?? c.value;\n }\n }\n return buildCookieHeader(map);\n}\n\n/** Load cookies from a flat cookie map (already parsed). */\nexport function loadCookiesFromMap(map: CookieMap): CookieMap {\n return { ...map };\n}\n\n/** Load cookies from a \"; \"-separated cookie string (e.g. process.env.NOTEBOOKLM_COOKIES). */\nexport function loadCookiesFromString(cookieStr: string): CookieMap {\n const map: CookieMap = {};\n for (const part of cookieStr.split(/;\\s*/)) {\n const idx = part.indexOf(\"=\");\n if (idx > 0) {\n const name = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (name) map[name] = value;\n }\n }\n return map;\n}\n\nfunction extractCookiesFromStorageState(storageState: {\n cookies?: Array<{ name: string; value: string; domain: string }>;\n}): CookieMap {\n const cookies: CookieMap = {};\n const domainTrack: Record<string, string> = {};\n\n for (const cookie of storageState.cookies ?? []) {\n const { domain, name, value } = cookie;\n if (!isAllowedDomain(domain) || !name) continue;\n\n const isBase = domain === \".google.com\";\n if (!(name in cookies) || isBase) {\n cookies[name] = value;\n domainTrack[name] = domain;\n }\n }\n\n if (!cookies[\"SID\"]) {\n throw new AuthError(\n \"Missing required cookie: SID. Session may be invalid or expired.\\nRun: npx notebooklm-sdk login\",\n );\n }\n return cookies;\n}\n\nfunction isAllowedDomain(domain: string): boolean {\n if (\n domain === \".google.com\" ||\n domain === \"notebooklm.google.com\" ||\n domain === \".googleusercontent.com\"\n ) {\n return true;\n }\n if (domain.startsWith(\".google.\")) {\n return true; // Allow all regional Google domains\n }\n return false;\n}\n\nexport function buildCookieHeader(cookies: CookieMap): string {\n return Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \");\n}\n\n// ---------------------------------------------------------------------------\n// Token fetching\n// ---------------------------------------------------------------------------\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\n\nexport async function fetchTokens(\n cookies: CookieMap,\n): Promise<{ csrfToken: string; sessionId: string }> {\n const cookieHeader = buildCookieHeader(cookies);\n\n const response = await fetch(NOTEBOOKLM_URL, {\n headers: { Cookie: cookieHeader },\n redirect: \"follow\",\n });\n\n if (!response.ok) {\n throw new AuthError(`Failed to fetch NotebookLM page: HTTP ${response.status}`);\n }\n\n const finalUrl = response.url;\n if (isGoogleAuthRedirect(finalUrl)) {\n throw new AuthError(`Redirected to login page: ${finalUrl}. Cookies may be expired.`);\n }\n\n const html = await response.text();\n const csrfToken = extractCsrfToken(html, finalUrl);\n const sessionId = extractSessionId(html, finalUrl);\n\n return { csrfToken, sessionId };\n}\n\nexport async function refreshAuthTokens(auth: AuthTokens): Promise<AuthTokens> {\n const { csrfToken, sessionId } = await fetchTokens(auth.cookies);\n auth.csrfToken = csrfToken;\n auth.sessionId = sessionId;\n return auth;\n}\n\nfunction extractCsrfToken(html: string, finalUrl: string): string {\n const match = /\"SNlM0e\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"CSRF token (SNlM0e) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction extractSessionId(html: string, finalUrl: string): string {\n const match = /\"FdrFJe\"\\s*:\\s*\"([^\"]+)\"/.exec(html);\n if (!match?.[1]) {\n if (isGoogleAuthRedirect(finalUrl) || html.includes(\"accounts.google.com\")) {\n throw new AuthError(\"Session expired or invalid.\\nRun: npx notebooklm-sdk login\");\n }\n throw new AuthError(\"Session ID (FdrFJe) not found in NotebookLM page HTML.\");\n }\n return match[1];\n}\n\nfunction isGoogleAuthRedirect(url: string): boolean {\n return url.includes(\"accounts.google.com\") || url.includes(\"signin\");\n}\n\n// ---------------------------------------------------------------------------\n// Connect options\n// ---------------------------------------------------------------------------\n\nexport interface ConnectOptions {\n /** \"; \"-separated cookie string (e.g. \"SID=abc; HSID=xyz\") */\n cookies?: string;\n /** Path to Playwright storage_state.json */\n cookiesFile?: string;\n /** Pre-parsed cookie map */\n cookiesObject?: CookieMap | { cookies?: Array<{ name: string; value: string; domain: string }> };\n}\n\nexport async function connect(opts: ConnectOptions = {}): Promise<AuthTokens> {\n let cookieMap: CookieMap;\n let googleCookieHeader: string | null = null;\n\n if (opts.cookies) {\n cookieMap = loadCookiesFromString(opts.cookies);\n } else if (opts.cookiesFile) {\n cookieMap = loadCookiesFromFile(opts.cookiesFile);\n } else if (opts.cookiesObject) {\n if (\"cookies\" in opts.cookiesObject && Array.isArray(opts.cookiesObject.cookies)) {\n const storageState = opts.cookiesObject as {\n cookies: Array<{ name: string; value: string; domain: string }>;\n };\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else {\n cookieMap = loadCookiesFromMap(opts.cookiesObject as CookieMap);\n }\n } else {\n // Auto-discovery: ~/.notebooklm/session.json → ./storage_state.json → env var\n const envCookies = process.env[\"NOTEBOOKLM_COOKIES\"];\n const envFile = process.env[\"NOTEBOOKLM_COOKIES_FILE\"];\n if (envFile) {\n cookieMap = loadCookiesFromFile(envFile);\n } else if (existsSync(DEFAULT_SESSION_FILE)) {\n const raw = readFileSync(DEFAULT_SESSION_FILE, \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (existsSync(\"storage_state.json\")) {\n const raw = readFileSync(\"storage_state.json\", \"utf-8\");\n const storageState = JSON.parse(raw);\n cookieMap = loadCookiesFromObject(storageState);\n googleCookieHeader = buildGoogleCookieHeader(storageState);\n } else if (envCookies) {\n cookieMap = loadCookiesFromString(envCookies);\n } else {\n throw new AuthError(\"No session found. Run: npx notebooklm-sdk login\");\n }\n }\n\n const { csrfToken, sessionId } = await fetchTokens(cookieMap);\n const cookieHeader = buildCookieHeader(cookieMap);\n\n return {\n cookies: cookieMap,\n csrfToken,\n sessionId,\n cookieHeader,\n googleCookieHeader: googleCookieHeader ?? cookieHeader,\n };\n}\n","import { existsSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type BrowserContext, chromium, type Page } from \"playwright\";\nimport { type CookieMap, loadCookiesFromObject } from \"../auth.js\";\n\n/** Default directory for storing NotebookLM session files (~/.notebooklm). */\nexport const DEFAULT_SESSION_DIR = join(homedir(), \".notebooklm\");\n/** Default session file path (~/.notebooklm/session.json). */\nexport const DEFAULT_SESSION_FILE = join(DEFAULT_SESSION_DIR, \"session.json\");\n\nexport interface LoginOptions {\n /**\n * Path to a directory for a persistent browser profile.\n * Defaults to ~/.notebooklm/.auth_profile.\n */\n persistFolder?: string;\n /**\n * Browser type to use. Default is \"chromium\".\n */\n browserType?: \"chromium\" | \"msedge\";\n /**\n * Whether to run the browser in headless mode. Default is false.\n * Headless login is usually blocked by Google, so this is mostly for testing or refreshes.\n */\n headless?: boolean;\n}\n\nconst NOTEBOOKLM_URL = \"https://notebooklm.google.com/\";\nconst GOOGLE_ACCOUNTS_URL = \"https://accounts.google.com/\";\n\n/**\n * Log in to NotebookLM via a headful browser window.\n *\n * Flow:\n * 1. Opens browser to NotebookLM.\n * 2. If already logged in (via persistFolder), it proceeds.\n * 3. If not, it waits for the user to reach the home page.\n * 4. Captures cookies and returns them.\n */\nexport async function login(opts: LoginOptions = {}): Promise<{\n cookies: CookieMap;\n storageState: any;\n cookieHeader: string;\n}> {\n const {\n persistFolder = join(DEFAULT_SESSION_DIR, \".auth_profile\"),\n headless = false,\n browserType = \"chromium\",\n } = opts;\n\n // Pre-flight: verify Playwright browser is installed\n try {\n chromium.executablePath();\n } catch {\n throw new Error(\"Playwright browser not found. Run: npx playwright install chromium\");\n }\n\n // Ensure the session directory exists\n if (!existsSync(DEFAULT_SESSION_DIR)) {\n mkdirSync(DEFAULT_SESSION_DIR, { recursive: true });\n }\n\n let context: BrowserContext;\n\n const launchOptions = {\n headless,\n args: [\"--disable-blink-features=AutomationControlled\"],\n };\n\n context = await chromium.launchPersistentContext(persistFolder, {\n ...launchOptions,\n channel: browserType === \"msedge\" ? \"msedge\" : undefined,\n });\n\n const page = context.pages()[0] || (await context.newPage());\n await page.goto(NOTEBOOKLM_URL);\n\n // Check if we are on the login page\n if (page.url().includes(\"accounts.google.com\")) {\n console.log(\"Please log in to Google in the browser window...\");\n\n // Wait for navigation back to NotebookLM or successful login indicator\n // We poll until the URL includes notebooklm.google.com and it's not a generic landing page\n await page.waitForURL(\n (url) => {\n return url.hostname === \"notebooklm.google.com\" && !url.pathname.includes(\"/login\");\n },\n { timeout: 0 },\n ); // No timeout, wait for user\n }\n\n // Ensure we are fully loaded on the accounts domain too to capture those cookies\n await page.goto(GOOGLE_ACCOUNTS_URL, { waitUntil: \"load\" });\n await page.goto(NOTEBOOKLM_URL, { waitUntil: \"load\" });\n\n const storageState = await context.storageState();\n const cookies = loadCookiesFromObject(storageState as any);\n\n await context.close();\n\n return {\n cookies,\n storageState,\n cookieHeader: Object.entries(cookies)\n .map(([k, v]) => `${k}=${v}`)\n .join(\"; \"),\n };\n}\n","#!/usr/bin/env node\nimport { writeFileSync } from \"node:fs\";\nimport { DEFAULT_SESSION_DIR, DEFAULT_SESSION_FILE, login } from \"./auth/browser.js\";\nimport { connect } from \"./auth.js\";\n\nasync function run() {\n const args = process.argv.slice(2);\n const command = args[0];\n\n if (command === \"login\") {\n console.log(\"Starting browser login flow...\");\n console.log(\"A browser window will open. Please log in to your Google account.\");\n\n try {\n const authResult = await login();\n\n writeFileSync(DEFAULT_SESSION_FILE, JSON.stringify(authResult.storageState, null, 2));\n\n console.log(\"\\nLogin successful!\");\n console.log(`Session saved to: ${DEFAULT_SESSION_FILE}`);\n console.log(\"\\nIn your code:\");\n console.log(\" const client = await NotebookLMClient.connect();\");\n } catch (error) {\n console.error(\"Login failed:\", error instanceof Error ? error.message : error);\n process.exit(1);\n }\n } else if (command === \"whoami\") {\n try {\n const auth = await connect();\n console.log(\"Session valid\");\n console.log(`Session file: ${DEFAULT_SESSION_FILE}`);\n console.log(`CSRF token: ${auth.csrfToken.slice(0, 8)}...`);\n } catch (error) {\n console.error(\"Not authenticated:\", error instanceof Error ? error.message : error);\n process.exit(1);\n }\n } else {\n console.log(\"NotebookLM SDK CLI\");\n console.log(\"\\nUsage:\");\n console.log(\" npx notebooklm-sdk login Authenticate via browser\");\n console.log(\" npx notebooklm-sdk whoami Check current session\");\n process.exit(command ? 1 : 0);\n }\n}\n\nrun();\n"]}