notebooklm-sdk 0.1.2 → 0.1.5

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,6 +1,15 @@
1
1
  # notebooklm-sdk
2
2
 
3
- A lightweight, zero-dependency TypeScript SDK for the NotebookLM API. Works with Node.js, Bun, and Deno.
3
+ [![npm version](https://img.shields.io/npm/v/notebooklm-sdk?style=flat-square)](https://www.npmjs.com/package/notebooklm-sdk)
4
+ ![types](https://img.shields.io/npm/types/notebooklm-sdk?style=flat-square)
5
+ ![license](https://img.shields.io/npm/l/notebooklm-sdk?style=flat-square)
6
+
7
+ A lightweight, zero-dependency TypeScript SDK for the NotebookLM API.
8
+ Works in **Node.js, Bun, and Deno**.
9
+
10
+ > This SDK is a TypeScript port of [notebooklm-py](https://github.com/teng-lin/notebooklm-py).
11
+
12
+ ---
4
13
 
5
14
  ## Installation
6
15
 
@@ -12,238 +21,289 @@ bun add notebooklm-sdk
12
21
 
13
22
  ## Authentication
14
23
 
15
- This SDK uses **manual cookie auth only** — no Playwright, no headless browser. You extract your cookies once and pass them in.
24
+ ### Quick Login (Recommended)
25
+
26
+ Run the built-in login script:
16
27
 
17
- **Option 1 — Raw cookie string** (from browser DevTools → Network tab → copy `Cookie` request header):
18
28
  ```bash
19
- NOTEBOOKLM_COOKIE="SID=...; HSID=...; ..."
29
+ bun run login
30
+ # or
31
+ npm run login
20
32
  ```
21
33
 
22
- **Option 2 Playwright `storage_state.json`** (JSON array of cookie objects):
34
+ This opens a real browser for Google sign-in and generates a
35
+ `storage_state.json` file you can reuse.
36
+
37
+ Then connect using the file:
38
+
39
+ ```ts
40
+ import { NotebookLMClient } from "notebooklm-sdk";
41
+
42
+ const client = await NotebookLMClient.connect({
43
+ cookiesFile: "./storage_state.json",
44
+ });
45
+ ```
46
+
47
+ Requires:
48
+
23
49
  ```bash
24
- NOTEBOOKLM_COOKIE='[{"name":"SID","value":"...","domain":".google.com",...}]'
50
+ npx playwright install chromium
25
51
  ```
26
52
 
27
- Then connect:
28
- ```typescript
29
- import { NotebookLMClient } from "notebooklm-sdk";
53
+ <details>
54
+ <summary>Manual Authentication</summary>
30
55
 
56
+ You can authenticate in multiple ways depending on your setup.
57
+
58
+ #### 1. Use `.env` Cookie String
59
+
60
+ Copy the `Cookie` header from DevTools → Network and store it:
61
+
62
+ ```bash
63
+ NOTEBOOKLM_COOKIE="SID=...; HSID=..."
64
+ ```
65
+
66
+ Then:
67
+
68
+ ```ts
31
69
  const client = await NotebookLMClient.connect({
32
70
  cookies: process.env.NOTEBOOKLM_COOKIE,
33
71
  });
34
72
  ```
35
73
 
36
- ## API Reference
74
+ ---
75
+
76
+ #### 2. Use Playwright `storage_state.json`
77
+
78
+ If you already have a Playwright storage file:
79
+
80
+ ```ts
81
+ const client = await NotebookLMClient.connect({
82
+ cookiesFile: "./storage_state.json",
83
+ });
84
+ ```
85
+
86
+ ---
37
87
 
38
- ### Notebooks
88
+ #### 3. Pass Cookies Directly
39
89
 
40
- ```typescript
90
+ You can also pass cookies at runtime:
91
+
92
+ ```ts
93
+ const client = await NotebookLMClient.connect({
94
+ cookies: "SID=...; HSID=...",
95
+ });
96
+ ```
97
+
98
+ </details>
99
+
100
+ ---
101
+
102
+ ## Notebooks
103
+
104
+ ```ts
41
105
  const notebooks = await client.notebooks.list();
42
- const nb = await client.notebooks.get(notebookId);
43
- const { notebookId } = await client.notebooks.create("My Notebook");
44
- await client.notebooks.rename(notebookId, "New Title");
45
- await client.notebooks.delete(notebookId);
106
+ const nb = await client.notebooks.get(id);
46
107
 
47
- const summary = await client.notebooks.getSummary(notebookId);
48
- const description = await client.notebooks.getDescription(notebookId);
49
- // description.summary, description.suggestedTopics
108
+ const { id: newId } = await client.notebooks.create("My Notebook");
109
+
110
+ await client.notebooks.rename(newId, "New Title");
111
+ await client.notebooks.delete(newId);
112
+
113
+ const summary = await client.notebooks.getSummary(id);
114
+ const description = await client.notebooks.getDescription(id);
50
115
  ```
51
116
 
52
- ### Sources
117
+ ---
53
118
 
54
- ```typescript
119
+ ## Sources
120
+
121
+ ```ts
55
122
  const sources = await client.sources.list(notebookId);
56
- const source = await client.sources.get(notebookId, sourceId);
57
123
 
58
- // Add sources
59
- const { sourceId } = await client.sources.addUrl(notebookId, "https://example.com");
60
- const { sourceId } = await client.sources.addText(notebookId, "My text", "My Title");
61
- const { sourceId } = await client.sources.addFile(notebookId, buffer, "file.pdf");
124
+ const { sourceId } = await client.sources.addUrl(
125
+ notebookId,
126
+ "https://example.com",
127
+ );
128
+ const { sourceId } = await client.sources.addText(notebookId, "Text", "Title");
129
+ const { sourceId } = await client.sources.addFile(
130
+ notebookId,
131
+ buffer,
132
+ "file.pdf",
133
+ );
62
134
 
63
- // Poll until ready (status: "ready")
64
- const source = await client.sources.waitUntilReady(notebookId, sourceId);
135
+ await client.sources.waitUntilReady(notebookId, sourceId);
65
136
 
66
137
  await client.sources.delete(notebookId, sourceId);
67
138
  ```
68
139
 
69
- ### Artifacts
140
+ ---
141
+
142
+ ## Artifacts
70
143
 
71
- Generate AI artifacts from notebook sources:
144
+ Generate AI outputs from notebook sources.
72
145
 
73
- ```typescript
74
- // Audio podcast
146
+ ```ts
75
147
  const { artifactId } = await client.artifacts.createAudio(notebookId, {
76
- format: AudioFormat.DEEP_DIVE, // DEEP_DIVE | BRIEF | CRITIQUE | DEBATE
77
- length: AudioLength.DEFAULT, // SHORT | DEFAULT | LONG
148
+ format: AudioFormat.DEEP_DIVE,
149
+ length: AudioLength.DEFAULT,
78
150
  language: "en",
79
151
  });
80
152
 
81
- // Video
82
153
  const { artifactId } = await client.artifacts.createVideo(notebookId, {
83
- format: VideoFormat.EXPLAINER, // EXPLAINER | BRIEF | CINEMATIC
154
+ format: VideoFormat.EXPLAINER,
84
155
  });
85
156
 
86
- // Quiz / Flashcards
87
- const { artifactId } = await client.artifacts.createQuiz(notebookId, {
88
- difficulty: QuizDifficulty.MEDIUM,
89
- quantity: QuizQuantity.STANDARD,
90
- });
157
+ const { artifactId } = await client.artifacts.createQuiz(notebookId);
91
158
  const { artifactId } = await client.artifacts.createFlashcards(notebookId);
92
159
 
93
- // Report (markdown)
94
160
  const { artifactId } = await client.artifacts.createReport(notebookId, {
95
- format: "briefing_doc", // "briefing_doc" | "study_guide" | "blog_post" | "custom"
96
- language: "en",
161
+ format: "briefing_doc",
97
162
  });
98
-
99
- // Other artifact types
100
- await client.artifacts.createInfographic(notebookId);
101
- await client.artifacts.createSlideDeck(notebookId);
102
- await client.artifacts.createMindMap(notebookId);
103
163
  ```
104
164
 
105
- Poll and download:
165
+ Wait & download:
106
166
 
107
- ```typescript
108
- // Wait until ready
109
- const artifact = await client.artifacts.waitUntilReady(notebookId, artifactId);
167
+ ```ts
168
+ await client.artifacts.waitUntilReady(notebookId, artifactId);
110
169
 
111
- // Download
112
- const audioBuffer = await client.artifacts.downloadAudio(notebookId, artifactId);
113
- const videoBuffer = await client.artifacts.downloadVideo(notebookId, artifactId);
114
- const markdown = await client.artifacts.getReportMarkdown(notebookId, artifactId);
115
- const html = await client.artifacts.getInteractiveHtml(notebookId, artifactId); // quiz/flashcards
170
+ const audio = await client.artifacts.downloadAudio(notebookId, artifactId);
171
+ const video = await client.artifacts.downloadVideo(notebookId, artifactId);
172
+
173
+ const markdown = await client.artifacts.getReportMarkdown(
174
+ notebookId,
175
+ artifactId,
176
+ );
177
+ const html = await client.artifacts.getInteractiveHtml(notebookId, artifactId);
116
178
  ```
117
179
 
118
- ### Chat
180
+ ---
181
+
182
+ ## Chat
119
183
 
120
- ```typescript
121
- // Ask a question
122
- const result = await client.chat.ask(notebookId, "What is this about?");
123
- console.log(result.answer);
124
- console.log(result.references); // [{ sourceId, title, url }]
184
+ ```ts
185
+ const res = await client.chat.ask(notebookId, "What is this about?");
186
+ console.log(res.answer);
125
187
 
126
- // Follow-up (pass conversationId to continue the thread)
127
- const result2 = await client.chat.ask(notebookId, "Tell me more.", {
128
- conversationId: result.conversationId,
188
+ const follow = await client.chat.ask(notebookId, "Tell me more.", {
189
+ conversationId: res.conversationId,
129
190
  });
130
191
 
131
- // Fetch conversation history
132
- const lastConvId = await client.chat.getLastConversationId(notebookId);
133
- const turns = await client.chat.getConversationTurns(notebookId, lastConvId);
192
+ const convId = await client.chat.getLastConversationId(notebookId);
193
+ const turns = await client.chat.getConversationTurns(notebookId, convId);
134
194
  ```
135
195
 
136
- ### Notes
196
+ ---
137
197
 
138
- ```typescript
139
- const { notes, mindMaps } = await client.notes.list(notebookId);
198
+ ## Notes
140
199
 
141
- const { noteId } = await client.notes.create(notebookId, "# My Note\n\nContent here.");
142
- await client.notes.update(notebookId, noteId, "Updated content.");
200
+ ```ts
201
+ const { noteId } = await client.notes.create(notebookId, "# My Note");
202
+
203
+ await client.notes.update(notebookId, noteId, "Updated");
143
204
  await client.notes.delete(notebookId, noteId);
144
205
  ```
145
206
 
146
- ### Research
207
+ ---
208
+
209
+ ## Research
147
210
 
148
- ```typescript
149
- // Start a fast web search or deep research
150
- const task = await client.research.start(notebookId, "Latest advances in quantum computing", "web", "deep");
211
+ ```ts
212
+ const task = await client.research.start(
213
+ notebookId,
214
+ "Latest advances in quantum computing",
215
+ "web",
216
+ "deep",
217
+ );
151
218
 
152
- // Poll for results
153
219
  const result = await client.research.poll(notebookId);
154
220
 
155
221
  if (result.status === "completed") {
156
- console.log(result.summary);
157
- console.log(`Found ${result.sources.length} sources.`);
158
-
159
- // Import desired sources into the notebook
160
- await client.research.importSources(notebookId, result.taskId, result.sources.slice(0, 2));
222
+ await client.research.importSources(
223
+ notebookId,
224
+ result.taskId,
225
+ result.sources.slice(0, 2),
226
+ );
161
227
  }
162
228
  ```
163
229
 
164
- ### Sharing
230
+ ---
165
231
 
166
- ```typescript
167
- const status = await client.sharing.getStatus(notebookId);
168
- // status.isPublic, status.sharedUsers, status.shareUrl
232
+ ## Sharing
169
233
 
170
- // Enable/disable public link sharing
234
+ ```ts
171
235
  await client.sharing.setPublic(notebookId, true);
172
236
 
173
- // Share with a specific user
174
- await client.sharing.addUser(notebookId, "user@example.com", SharePermission.VIEWER);
175
- await client.sharing.updateUser(notebookId, "user@example.com", SharePermission.EDITOR);
176
- await client.sharing.removeUser(notebookId, "user@example.com");
237
+ await client.sharing.addUser(
238
+ notebookId,
239
+ "user@example.com",
240
+ SharePermission.VIEWER,
241
+ );
177
242
  ```
178
243
 
179
- ### Settings
244
+ ---
180
245
 
181
- ```typescript
182
- const lang = await client.settings.getOutputLanguage(); // "en"
246
+ ## Settings
247
+
248
+ ```ts
249
+ const lang = await client.settings.getOutputLanguage();
183
250
  await client.settings.setOutputLanguage("ja");
184
251
  ```
185
252
 
253
+ ---
254
+
186
255
  ## Examples
187
256
 
188
- Runnable scripts in [`examples/`](./examples). Requires `.env` with `NOTEBOOKLM_COOKIE`.
257
+ Runnable scripts are in [`examples/`](./examples).
258
+
259
+ Requires `.env`:
189
260
 
190
- | Script | What it does |
191
- |--------|-------------|
192
- | `basic.ts` | List notebooks and sources |
193
- | `report.ts` | Generate and download a report |
194
- | `audio.ts` | Generate a podcast (long wait) |
195
- | `download.ts` | Download all completed artifacts (audio, video, reports, quiz, flashcards) |
196
- | `chat.ts` | Ask questions and follow up |
197
- | `research.ts` | Start a web research session and import sources |
198
- | `settings.ts` | Check output language and sharing status |
261
+ ```
262
+ NOTEBOOKLM_COOKIE=...
263
+ ```
264
+
265
+ Run:
199
266
 
200
267
  ```bash
268
+ # for auto login
269
+ bun run login
270
+ bun run examples/basic.ts
271
+
272
+ # for manual cookie
201
273
  bunx dotenv -e .env -- bunx tsx examples/basic.ts
202
274
  ```
203
275
 
204
- ## Error Handling
276
+ ---
205
277
 
206
- All errors extend `NotebookLMError`:
278
+ ## Error Handling
207
279
 
208
- ```typescript
209
- import { ArtifactNotReadyError, AuthError, RateLimitError } from "notebooklm-sdk";
280
+ All errors extend `NotebookLMError`.
210
281
 
282
+ ```ts
211
283
  try {
212
284
  await client.artifacts.downloadAudio(notebookId, artifactId);
213
285
  } catch (err) {
214
- if (err instanceof ArtifactNotReadyError) { /* artifact still processing */ }
215
- if (err instanceof AuthError) { /* cookies expired */ }
216
- if (err instanceof RateLimitError) { /* back off */ }
286
+ if (err instanceof ArtifactNotReadyError) {
287
+ // still processing
288
+ }
217
289
  }
218
290
  ```
219
291
 
220
- Error classes: `AuthError`, `RateLimitError`, `NetworkError`, `ServerError`, `RPCError`, `RPCTimeoutError`, `ArtifactNotReadyError`, `ArtifactNotFoundError`, `SourceAddError`, `SourceProcessingError`, `SourceTimeoutError`, and more.
292
+ ---
221
293
 
222
294
  ## Project Structure
223
295
 
224
296
  ```
225
297
  src/
226
- ├── client.ts — NotebookLMClient
227
- ├── auth.ts — Cookie auth, token fetching
228
- ├── index.ts — Public exports
229
- ├── api/
230
- │ ├── artifacts.ts — Audio, video, quiz, report, slide deck, infographic, mind map
231
- │ ├── chat.ts — Chat / Q&A
232
- │ ├── notebooks.ts — CRUD + summary
233
- │ ├── notes.ts — Notes + mind maps
234
- │ ├── settings.ts — User settings
235
- │ ├── sharing.ts — Notebook sharing
236
- │ └── sources.ts — URL, text, file sources
237
- ├── rpc/
238
- │ ├── core.ts — HTTP + decode pipeline
239
- │ ├── encoder.ts — Request encoding
240
- │ └── decoder.ts — Response decoding
241
- └── types/
242
- ├── enums.ts — RPC method IDs, format options, status codes
243
- ├── errors.ts — Error hierarchy
244
- └── models.ts — Interfaces + response parsers
298
+ client.ts
299
+ auth.ts
300
+ api/
301
+ rpc/
302
+ types/
245
303
  ```
246
304
 
305
+ ---
306
+
247
307
  ## License
248
308
 
249
309
  MIT
@@ -0,0 +1,55 @@
1
+ interface CookieMap {
2
+ [key: string]: string;
3
+ }
4
+ interface AuthTokens {
5
+ cookies: CookieMap;
6
+ csrfToken: string;
7
+ sessionId: string;
8
+ cookieHeader: string;
9
+ /** Cookie header containing only .google.com domain cookies — for media downloads */
10
+ googleCookieHeader: string;
11
+ }
12
+ /** Load cookies from a Playwright storage_state.json file. */
13
+ declare function loadCookiesFromFile(filePath: string): CookieMap;
14
+ /** Load cookies from a raw Playwright storage state object. */
15
+ declare function loadCookiesFromObject(storageState: {
16
+ cookies?: Array<{
17
+ name: string;
18
+ value: string;
19
+ domain: string;
20
+ }>;
21
+ }): CookieMap;
22
+ /** Build a cookie header containing only .google.com domain cookies (for media downloads). */
23
+ declare function buildGoogleCookieHeader(storageState: {
24
+ cookies?: Array<{
25
+ name: string;
26
+ value: string;
27
+ domain: string;
28
+ }>;
29
+ }): string;
30
+ /** Load cookies from a flat cookie map (already parsed). */
31
+ declare function loadCookiesFromMap(map: CookieMap): CookieMap;
32
+ /** Load cookies from a "; "-separated cookie string (e.g. process.env.NOTEBOOKLM_COOKIES). */
33
+ declare function loadCookiesFromString(cookieStr: string): CookieMap;
34
+ declare function buildCookieHeader(cookies: CookieMap): string;
35
+ declare function fetchTokens(cookies: CookieMap): Promise<{
36
+ csrfToken: string;
37
+ sessionId: string;
38
+ }>;
39
+ interface ConnectOptions {
40
+ /** "; "-separated cookie string (e.g. "SID=abc; HSID=xyz") */
41
+ cookies?: string;
42
+ /** Path to Playwright storage_state.json */
43
+ cookiesFile?: string;
44
+ /** Pre-parsed cookie map */
45
+ cookiesObject?: CookieMap | {
46
+ cookies?: Array<{
47
+ name: string;
48
+ value: string;
49
+ domain: string;
50
+ }>;
51
+ };
52
+ }
53
+ declare function connect(opts: ConnectOptions): Promise<AuthTokens>;
54
+
55
+ export { type AuthTokens as A, type ConnectOptions as C, type CookieMap as a, buildCookieHeader as b, connect as c, buildGoogleCookieHeader as d, loadCookiesFromMap as e, fetchTokens as f, loadCookiesFromObject as g, loadCookiesFromString as h, loadCookiesFromFile as l };
@@ -0,0 +1,55 @@
1
+ interface CookieMap {
2
+ [key: string]: string;
3
+ }
4
+ interface AuthTokens {
5
+ cookies: CookieMap;
6
+ csrfToken: string;
7
+ sessionId: string;
8
+ cookieHeader: string;
9
+ /** Cookie header containing only .google.com domain cookies — for media downloads */
10
+ googleCookieHeader: string;
11
+ }
12
+ /** Load cookies from a Playwright storage_state.json file. */
13
+ declare function loadCookiesFromFile(filePath: string): CookieMap;
14
+ /** Load cookies from a raw Playwright storage state object. */
15
+ declare function loadCookiesFromObject(storageState: {
16
+ cookies?: Array<{
17
+ name: string;
18
+ value: string;
19
+ domain: string;
20
+ }>;
21
+ }): CookieMap;
22
+ /** Build a cookie header containing only .google.com domain cookies (for media downloads). */
23
+ declare function buildGoogleCookieHeader(storageState: {
24
+ cookies?: Array<{
25
+ name: string;
26
+ value: string;
27
+ domain: string;
28
+ }>;
29
+ }): string;
30
+ /** Load cookies from a flat cookie map (already parsed). */
31
+ declare function loadCookiesFromMap(map: CookieMap): CookieMap;
32
+ /** Load cookies from a "; "-separated cookie string (e.g. process.env.NOTEBOOKLM_COOKIES). */
33
+ declare function loadCookiesFromString(cookieStr: string): CookieMap;
34
+ declare function buildCookieHeader(cookies: CookieMap): string;
35
+ declare function fetchTokens(cookies: CookieMap): Promise<{
36
+ csrfToken: string;
37
+ sessionId: string;
38
+ }>;
39
+ interface ConnectOptions {
40
+ /** "; "-separated cookie string (e.g. "SID=abc; HSID=xyz") */
41
+ cookies?: string;
42
+ /** Path to Playwright storage_state.json */
43
+ cookiesFile?: string;
44
+ /** Pre-parsed cookie map */
45
+ cookiesObject?: CookieMap | {
46
+ cookies?: Array<{
47
+ name: string;
48
+ value: string;
49
+ domain: string;
50
+ }>;
51
+ };
52
+ }
53
+ declare function connect(opts: ConnectOptions): Promise<AuthTokens>;
54
+
55
+ export { type AuthTokens as A, type ConnectOptions as C, type CookieMap as a, buildCookieHeader as b, connect as c, buildGoogleCookieHeader as d, loadCookiesFromMap as e, fetchTokens as f, loadCookiesFromObject as g, loadCookiesFromString as h, loadCookiesFromFile as l };