notebooklm-sdk 0.1.4 → 0.1.6

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