@@ -47,32 +47,66 @@ function isAllowedDomain(domain: string): boolean {
4747}
4848
4949/**
50- * Parse the Playwright storage state JSON from the env var.
50+ * Load the Playwright storage state JSON from env var or file path.
51+ *
52+ * Supports three modes:
53+ * 1. NOTEBOOKLM_AUTH_JSON contains raw JSON: {"cookies": [...]}
54+ * 2. NOTEBOOKLM_AUTH_JSON contains a file path: ~/.notebooklm/storage_state.json
55+ * 3. NOTEBOOKLM_AUTH_JSON contains double-quoted JSON (from .env.local quoting)
5156 */
5257function parseCookiesFromEnv ( ) : Record < string , string > {
5358 const authJson = process . env . NOTEBOOKLM_AUTH_JSON ;
5459 if ( ! authJson ) {
5560 throw new Error (
5661 '[NotebookLM] NOTEBOOKLM_AUTH_JSON env var is not set. ' +
57- 'Set it to a Playwright storage state JSON with Google cookies.'
62+ 'Set it to a file path (e.g., ~/.notebooklm/storage_state.json) ' +
63+ 'or inline Playwright storage state JSON.'
5864 ) ;
5965 }
6066
6167 let storageState : { cookies ?: NotebookLMCookie [ ] } ;
62- try {
63- // .env.local may double-quote the value, producing a JSON string literal.
64- // Try parsing once; if the result is a string, parse again.
65- let parsed : unknown = JSON . parse ( authJson ) ;
66- if ( typeof parsed === 'string' ) {
67- parsed = JSON . parse ( parsed ) ;
68+
69+ // Check if the value looks like a file path (doesn't start with { or ")
70+ const trimmed = authJson . trim ( ) ;
71+ if ( ! trimmed . startsWith ( '{' ) && ! trimmed . startsWith ( '"' ) && ! trimmed . startsWith ( "'" ) ) {
72+ // Treat as file path — resolve ~ to home directory
73+ try {
74+ // eslint-disable-next-line @typescript-eslint/no-require-imports
75+ const fs = require ( 'fs' ) as typeof import ( 'fs' ) ;
76+ // eslint-disable-next-line @typescript-eslint/no-require-imports
77+ const path = require ( 'path' ) as typeof import ( 'path' ) ;
78+ // eslint-disable-next-line @typescript-eslint/no-require-imports
79+ const os = require ( 'os' ) as typeof import ( 'os' ) ;
80+
81+ const resolvedPath = trimmed . startsWith ( '~' )
82+ ? path . join ( os . homedir ( ) , trimmed . slice ( 1 ) )
83+ : path . resolve ( trimmed ) ;
84+
85+ console . log ( `[NotebookLM] Loading auth from file: ${ resolvedPath } ` ) ;
86+ const fileContent = fs . readFileSync ( resolvedPath , 'utf-8' ) ;
87+ storageState = JSON . parse ( fileContent ) as { cookies ?: NotebookLMCookie [ ] } ;
88+ } catch ( err ) {
89+ throw new Error (
90+ `[NotebookLM] Failed to read auth file "${ trimmed } ": ${ err instanceof Error ? err . message : String ( err ) } `
91+ ) ;
92+ }
93+ } else {
94+ // Treat as inline JSON
95+ try {
96+ // .env.local may double-quote the value, producing a JSON string literal.
97+ // Try parsing once; if the result is a string, parse again.
98+ let parsed : unknown = JSON . parse ( trimmed ) ;
99+ if ( typeof parsed === 'string' ) {
100+ parsed = JSON . parse ( parsed ) ;
101+ }
102+ storageState = parsed as { cookies ?: NotebookLMCookie [ ] } ;
103+ } catch {
104+ throw new Error (
105+ '[NotebookLM] NOTEBOOKLM_AUTH_JSON is not valid JSON and not a valid file path. ' +
106+ 'Set it to a file path (e.g., ~/.notebooklm/storage_state.json) ' +
107+ 'or valid Playwright storage state JSON: {"cookies": [...]}'
108+ ) ;
68109 }
69- storageState = parsed as { cookies ?: NotebookLMCookie [ ] } ;
70- } catch {
71- throw new Error (
72- '[NotebookLM] NOTEBOOKLM_AUTH_JSON is not valid JSON. ' +
73- 'Expected Playwright storage state format: {"cookies": [...]}. ' +
74- 'Tip: In .env.local, set it without wrapping quotes: NOTEBOOKLM_AUTH_JSON={"cookies":[...]}'
75- ) ;
76110 }
77111
78112 const rawCookies = storageState . cookies ;
0 commit comments