notebooklm-sdk 0.1.4 → 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,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,194 @@ 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
+ Run the built-in login script:
20
27
 
21
28
  ```bash
22
- NOTEBOOKLM_COOKIE="SID=...; HSID=...; ..."
29
+ bun run login
30
+ # or
31
+ npm run login
32
+ ```
33
+
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
+ });
23
45
  ```
24
46
 
25
- **Option 2 — Playwright `storage_state.json`** (JSON array of cookie objects):
47
+ Requires:
26
48
 
27
49
  ```bash
28
- NOTEBOOKLM_COOKIE='[{"name":"SID","value":"...","domain":".google.com",...}]'
50
+ npx playwright install chromium
29
51
  ```
30
52
 
31
- Then connect:
53
+ <details>
54
+ <summary>Manual Authentication</summary>
32
55
 
33
- ```typescript
34
- import { NotebookLMClient } from "notebooklm-sdk";
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:
35
67
 
68
+ ```ts
36
69
  const client = await NotebookLMClient.connect({
37
70
  cookies: process.env.NOTEBOOKLM_COOKIE,
38
71
  });
39
72
  ```
40
73
 
41
- ## API Reference
74
+ ---
42
75
 
43
- ### Notebooks
76
+ #### 2. Use Playwright `storage_state.json`
44
77
 
45
- ```typescript
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
+ ---
87
+
88
+ #### 3. Pass Cookies Directly
89
+
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
46
105
  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
106
+ const nb = await client.notebooks.get(id);
107
+
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);
55
115
  ```
56
116
 
57
- ### Sources
117
+ ---
58
118
 
59
- ```typescript
119
+ ## Sources
120
+
121
+ ```ts
60
122
  const sources = await client.sources.list(notebookId);
61
- const source = await client.sources.get(notebookId, sourceId);
62
123
 
63
- // Add sources
64
124
  const { sourceId } = await client.sources.addUrl(
65
125
  notebookId,
66
126
  "https://example.com",
67
127
  );
68
- const { sourceId } = await client.sources.addText(
69
- notebookId,
70
- "My text",
71
- "My Title",
72
- );
128
+ const { sourceId } = await client.sources.addText(notebookId, "Text", "Title");
73
129
  const { sourceId } = await client.sources.addFile(
74
130
  notebookId,
75
131
  buffer,
76
132
  "file.pdf",
77
133
  );
78
134
 
79
- // Poll until ready (status: "ready")
80
- const source = await client.sources.waitUntilReady(notebookId, sourceId);
135
+ await client.sources.waitUntilReady(notebookId, sourceId);
81
136
 
82
137
  await client.sources.delete(notebookId, sourceId);
83
138
  ```
84
139
 
85
- ### Artifacts
140
+ ---
86
141
 
87
- Generate AI artifacts from notebook sources:
142
+ ## Artifacts
88
143
 
89
- ```typescript
90
- // Audio podcast
144
+ Generate AI outputs from notebook sources.
145
+
146
+ ```ts
91
147
  const { artifactId } = await client.artifacts.createAudio(notebookId, {
92
- format: AudioFormat.DEEP_DIVE, // DEEP_DIVE | BRIEF | CRITIQUE | DEBATE
93
- length: AudioLength.DEFAULT, // SHORT | DEFAULT | LONG
148
+ format: AudioFormat.DEEP_DIVE,
149
+ length: AudioLength.DEFAULT,
94
150
  language: "en",
95
151
  });
96
152
 
97
- // Video
98
153
  const { artifactId } = await client.artifacts.createVideo(notebookId, {
99
- format: VideoFormat.EXPLAINER, // EXPLAINER | BRIEF | CINEMATIC
154
+ format: VideoFormat.EXPLAINER,
100
155
  });
101
156
 
102
- // Quiz / Flashcards
103
- const { artifactId } = await client.artifacts.createQuiz(notebookId, {
104
- difficulty: QuizDifficulty.MEDIUM,
105
- quantity: QuizQuantity.STANDARD,
106
- });
157
+ const { artifactId } = await client.artifacts.createQuiz(notebookId);
107
158
  const { artifactId } = await client.artifacts.createFlashcards(notebookId);
108
159
 
109
- // Report (markdown)
110
160
  const { artifactId } = await client.artifacts.createReport(notebookId, {
111
- format: "briefing_doc", // "briefing_doc" | "study_guide" | "blog_post" | "custom"
112
- language: "en",
161
+ format: "briefing_doc",
113
162
  });
114
-
115
- // Other artifact types
116
- await client.artifacts.createInfographic(notebookId);
117
- await client.artifacts.createSlideDeck(notebookId);
118
- await client.artifacts.createMindMap(notebookId);
119
163
  ```
120
164
 
121
- Poll and download:
165
+ Wait & download:
122
166
 
123
- ```typescript
124
- // Wait until ready
125
- const artifact = await client.artifacts.waitUntilReady(notebookId, artifactId);
167
+ ```ts
168
+ await client.artifacts.waitUntilReady(notebookId, artifactId);
169
+
170
+ const audio = await client.artifacts.downloadAudio(notebookId, artifactId);
171
+ const video = await client.artifacts.downloadVideo(notebookId, artifactId);
126
172
 
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
173
  const markdown = await client.artifacts.getReportMarkdown(
137
174
  notebookId,
138
175
  artifactId,
139
176
  );
140
- const html = await client.artifacts.getInteractiveHtml(notebookId, artifactId); // quiz/flashcards
177
+ const html = await client.artifacts.getInteractiveHtml(notebookId, artifactId);
141
178
  ```
142
179
 
143
- ### Chat
180
+ ---
144
181
 
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 }]
182
+ ## Chat
150
183
 
151
- // Follow-up (pass conversationId to continue the thread)
152
- const result2 = await client.chat.ask(notebookId, "Tell me more.", {
153
- conversationId: result.conversationId,
184
+ ```ts
185
+ const res = await client.chat.ask(notebookId, "What is this about?");
186
+ console.log(res.answer);
187
+
188
+ const follow = await client.chat.ask(notebookId, "Tell me more.", {
189
+ conversationId: res.conversationId,
154
190
  });
155
191
 
156
- // Fetch conversation history
157
- const lastConvId = await client.chat.getLastConversationId(notebookId);
158
- 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);
159
194
  ```
160
195
 
161
- ### Notes
196
+ ---
162
197
 
163
- ```typescript
164
- const { notes, mindMaps } = await client.notes.list(notebookId);
198
+ ## Notes
165
199
 
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.");
200
+ ```ts
201
+ const { noteId } = await client.notes.create(notebookId, "# My Note");
202
+
203
+ await client.notes.update(notebookId, noteId, "Updated");
171
204
  await client.notes.delete(notebookId, noteId);
172
205
  ```
173
206
 
174
- ### Research
207
+ ---
175
208
 
176
- ```typescript
177
- // Start a fast web search or deep research
209
+ ## Research
210
+
211
+ ```ts
178
212
  const task = await client.research.start(
179
213
  notebookId,
180
214
  "Latest advances in quantum computing",
@@ -182,14 +216,9 @@ const task = await client.research.start(
182
216
  "deep",
183
217
  );
184
218
 
185
- // Poll for results
186
219
  const result = await client.research.poll(notebookId);
187
220
 
188
221
  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
222
  await client.research.importSources(
194
223
  notebookId,
195
224
  result.taskId,
@@ -198,109 +227,83 @@ if (result.status === "completed") {
198
227
  }
199
228
  ```
200
229
 
201
- ### Sharing
230
+ ---
202
231
 
203
- ```typescript
204
- const status = await client.sharing.getStatus(notebookId);
205
- // status.isPublic, status.sharedUsers, status.shareUrl
232
+ ## Sharing
206
233
 
207
- // Enable/disable public link sharing
234
+ ```ts
208
235
  await client.sharing.setPublic(notebookId, true);
209
236
 
210
- // Share with a specific user
211
237
  await client.sharing.addUser(
212
238
  notebookId,
213
239
  "user@example.com",
214
240
  SharePermission.VIEWER,
215
241
  );
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
242
  ```
223
243
 
224
- ### Settings
244
+ ---
225
245
 
226
- ```typescript
227
- const lang = await client.settings.getOutputLanguage(); // "en"
246
+ ## Settings
247
+
248
+ ```ts
249
+ const lang = await client.settings.getOutputLanguage();
228
250
  await client.settings.setOutputLanguage("ja");
229
251
  ```
230
252
 
253
+ ---
254
+
231
255
  ## Examples
232
256
 
233
- Runnable scripts in [`examples/`](./examples). Requires `.env` with `NOTEBOOKLM_COOKIE`.
257
+ Runnable scripts are in [`examples/`](./examples).
234
258
 
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 |
259
+ Requires `.env`:
260
+
261
+ ```
262
+ NOTEBOOKLM_COOKIE=...
263
+ ```
264
+
265
+ Run:
246
266
 
247
267
  ```bash
268
+ # for auto login
269
+ bun run login
270
+ bun run examples/basic.ts
271
+
272
+ # for manual cookie
248
273
  bunx dotenv -e .env -- bunx tsx examples/basic.ts
249
274
  ```
250
275
 
251
- ## Error Handling
276
+ ---
252
277
 
253
- All errors extend `NotebookLMError`:
278
+ ## Error Handling
254
279
 
255
- ```typescript
256
- import {
257
- ArtifactNotReadyError,
258
- AuthError,
259
- RateLimitError,
260
- } from "notebooklm-sdk";
280
+ All errors extend `NotebookLMError`.
261
281
 
282
+ ```ts
262
283
  try {
263
284
  await client.artifacts.downloadAudio(notebookId, artifactId);
264
285
  } catch (err) {
265
286
  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 */
287
+ // still processing
273
288
  }
274
289
  }
275
290
  ```
276
291
 
277
- Error classes: `AuthError`, `RateLimitError`, `NetworkError`, `ServerError`, `RPCError`, `RPCTimeoutError`, `ArtifactNotReadyError`, `ArtifactNotFoundError`, `SourceAddError`, `SourceProcessingError`, `SourceTimeoutError`, and more.
292
+ ---
278
293
 
279
294
  ## Project Structure
280
295
 
281
296
  ```
282
297
  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
298
+ client.ts
299
+ auth.ts
300
+ api/
301
+ rpc/
302
+ types/
302
303
  ```
303
304
 
305
+ ---
306
+
304
307
  ## License
305
308
 
306
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 };