notebooklm-kit 0.0.1 → 2.1.1

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.
Files changed (100) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +4102 -0
  3. package/dist/src/auth/auth.d.ts +46 -0
  4. package/dist/src/auth/auth.d.ts.map +1 -0
  5. package/dist/src/auth/auth.js +323 -0
  6. package/dist/src/auth/auth.js.map +1 -0
  7. package/dist/src/auth/refresh.d.ts +150 -0
  8. package/dist/src/auth/refresh.d.ts.map +1 -0
  9. package/dist/src/auth/refresh.js +433 -0
  10. package/dist/src/auth/refresh.js.map +1 -0
  11. package/dist/src/client/notebooklm-client.d.ts +372 -0
  12. package/dist/src/client/notebooklm-client.d.ts.map +1 -0
  13. package/dist/src/client/notebooklm-client.js +550 -0
  14. package/dist/src/client/notebooklm-client.js.map +1 -0
  15. package/dist/src/index.d.ts +50 -0
  16. package/dist/src/index.d.ts.map +1 -0
  17. package/dist/src/index.js +45 -0
  18. package/dist/src/index.js.map +1 -0
  19. package/dist/src/rpc/rpc-client.d.ts +48 -0
  20. package/dist/src/rpc/rpc-client.d.ts.map +1 -0
  21. package/dist/src/rpc/rpc-client.js +94 -0
  22. package/dist/src/rpc/rpc-client.js.map +1 -0
  23. package/dist/src/rpc/rpc-methods.d.ts +127 -0
  24. package/dist/src/rpc/rpc-methods.d.ts.map +1 -0
  25. package/dist/src/rpc/rpc-methods.js +169 -0
  26. package/dist/src/rpc/rpc-methods.js.map +1 -0
  27. package/dist/src/services/artifacts.d.ts +1017 -0
  28. package/dist/src/services/artifacts.d.ts.map +1 -0
  29. package/dist/src/services/artifacts.js +5413 -0
  30. package/dist/src/services/artifacts.js.map +1 -0
  31. package/dist/src/services/generation.d.ts +147 -0
  32. package/dist/src/services/generation.d.ts.map +1 -0
  33. package/dist/src/services/generation.js +479 -0
  34. package/dist/src/services/generation.js.map +1 -0
  35. package/dist/src/services/notebook-language.d.ts +109 -0
  36. package/dist/src/services/notebook-language.d.ts.map +1 -0
  37. package/dist/src/services/notebook-language.js +204 -0
  38. package/dist/src/services/notebook-language.js.map +1 -0
  39. package/dist/src/services/notebooks.d.ts +26 -0
  40. package/dist/src/services/notebooks.d.ts.map +1 -0
  41. package/dist/src/services/notebooks.js +539 -0
  42. package/dist/src/services/notebooks.js.map +1 -0
  43. package/dist/src/services/notes.d.ts +72 -0
  44. package/dist/src/services/notes.d.ts.map +1 -0
  45. package/dist/src/services/notes.js +340 -0
  46. package/dist/src/services/notes.js.map +1 -0
  47. package/dist/src/services/sources.d.ts +1085 -0
  48. package/dist/src/services/sources.d.ts.map +1 -0
  49. package/dist/src/services/sources.js +2675 -0
  50. package/dist/src/services/sources.js.map +1 -0
  51. package/dist/src/types/artifact.d.ts +258 -0
  52. package/dist/src/types/artifact.d.ts.map +1 -0
  53. package/dist/src/types/artifact.js +42 -0
  54. package/dist/src/types/artifact.js.map +1 -0
  55. package/dist/src/types/common.d.ts +226 -0
  56. package/dist/src/types/common.d.ts.map +1 -0
  57. package/dist/src/types/common.js +80 -0
  58. package/dist/src/types/common.js.map +1 -0
  59. package/dist/src/types/languages.d.ts +179 -0
  60. package/dist/src/types/languages.d.ts.map +1 -0
  61. package/dist/src/types/languages.js +254 -0
  62. package/dist/src/types/languages.js.map +1 -0
  63. package/dist/src/types/note.d.ts +41 -0
  64. package/dist/src/types/note.d.ts.map +1 -0
  65. package/dist/src/types/note.js +12 -0
  66. package/dist/src/types/note.js.map +1 -0
  67. package/dist/src/types/notebook.d.ts +81 -0
  68. package/dist/src/types/notebook.d.ts.map +1 -0
  69. package/dist/src/types/notebook.js +5 -0
  70. package/dist/src/types/notebook.js.map +1 -0
  71. package/dist/src/types/source.d.ts +241 -0
  72. package/dist/src/types/source.d.ts.map +1 -0
  73. package/dist/src/types/source.js +60 -0
  74. package/dist/src/types/source.js.map +1 -0
  75. package/dist/src/utils/batch-execute.d.ts +58 -0
  76. package/dist/src/utils/batch-execute.d.ts.map +1 -0
  77. package/dist/src/utils/batch-execute.js +398 -0
  78. package/dist/src/utils/batch-execute.js.map +1 -0
  79. package/dist/src/utils/chunked-decoder.d.ts +11 -0
  80. package/dist/src/utils/chunked-decoder.d.ts.map +1 -0
  81. package/dist/src/utils/chunked-decoder.js +326 -0
  82. package/dist/src/utils/chunked-decoder.js.map +1 -0
  83. package/dist/src/utils/chunked-parser.d.ts +61 -0
  84. package/dist/src/utils/chunked-parser.d.ts.map +1 -0
  85. package/dist/src/utils/chunked-parser.js +609 -0
  86. package/dist/src/utils/chunked-parser.js.map +1 -0
  87. package/dist/src/utils/errors.d.ts +58 -0
  88. package/dist/src/utils/errors.d.ts.map +1 -0
  89. package/dist/src/utils/errors.js +357 -0
  90. package/dist/src/utils/errors.js.map +1 -0
  91. package/dist/src/utils/quota.d.ts +213 -0
  92. package/dist/src/utils/quota.d.ts.map +1 -0
  93. package/dist/src/utils/quota.js +518 -0
  94. package/dist/src/utils/quota.js.map +1 -0
  95. package/dist/src/utils/streaming-client.d.ts +129 -0
  96. package/dist/src/utils/streaming-client.d.ts.map +1 -0
  97. package/dist/src/utils/streaming-client.js +559 -0
  98. package/dist/src/utils/streaming-client.js.map +1 -0
  99. package/package.json +85 -7
  100. package/index.js +0 -2
package/README.md ADDED
@@ -0,0 +1,4102 @@
1
+ <div align="center">
2
+
3
+ # @photon-ai/NotebookLM-kit
4
+
5
+ > A TypeScript SDK for programmatic access to Google NotebookLM.
6
+
7
+ </div>
8
+
9
+ [![npm version](https://img.shields.io/npm/v/notebooklm-kit.svg)](https://www.npmjs.com/package/notebooklm-kit)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)
11
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
12
+ [![Discord](https://img.shields.io/badge/Discord-Join-5865F2.svg?logo=discord&logoColor=white)](https://discord.gg/bZd4CMd2H5)
13
+
14
+ ## Overview
15
+
16
+ The NotebookLM Kit provides a clean, service-based interface to all NotebookLM features. Perfect for building AI research assistants, study tools, content generators, and automated knowledge management systems.
17
+
18
+ > [!NOTE]
19
+ > **✨ Looking for advanced features, custom integrations, or enterprise support? Contact us at [vandit@photon.codes](mailto:vandit@photon.codes).**
20
+
21
+ ## Features
22
+
23
+ <table>
24
+ <thead>
25
+ <tr>
26
+ <th>Feature</th>
27
+ <th>Method</th>
28
+ <th>Example</th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
33
+ <tr>
34
+ <td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#notebooks">Notebook Management</a></strong> <small><code>list()</code>, <code>create()</code>, <code>get()</code>, <code>update()</code>, <code>delete()</code>, <code>share()</code></small></td>
35
+ </tr>
36
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
37
+ <tr>
38
+ <td>List Notebooks</td>
39
+ <td><code>sdk.notebooks.list()</code></td>
40
+ <td><a href="examples/notebook-list.ts">notebook-list.ts</a></td>
41
+ </tr>
42
+ <tr>
43
+ <td>Create Notebook</td>
44
+ <td><code>sdk.notebooks.create()</code></td>
45
+ <td><a href="examples/notebook-create.ts">notebook-create.ts</a></td>
46
+ </tr>
47
+ <tr>
48
+ <td>Get Notebook</td>
49
+ <td><code>sdk.notebooks.get()</code></td>
50
+ <td><a href="examples/notebook-get.ts">notebook-get.ts</a></td>
51
+ </tr>
52
+ <tr>
53
+ <td>Update Notebook</td>
54
+ <td><code>sdk.notebooks.update()</code></td>
55
+ <td><a href="examples/notebook-update.ts">notebook-update.ts</a></td>
56
+ </tr>
57
+ <tr>
58
+ <td>Delete Notebook</td>
59
+ <td><code>sdk.notebooks.delete()</code></td>
60
+ <td><a href="examples/notebook-delete.ts">notebook-delete.ts</a></td>
61
+ </tr>
62
+ <tr>
63
+ <td>Share Notebook</td>
64
+ <td><code>sdk.notebooks.share()</code></td>
65
+ <td><a href="examples/notebook-share.ts">notebook-share.ts</a></td>
66
+ </tr>
67
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
68
+ <tr>
69
+ <td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#sources">Source Management</a></strong> <small><code>list()</code>, <code>get()</code>, <code>add.url()</code>, <code>add.text()</code>, <code>add.youtube()</code>, <code>add.file()</code>, <code>add.drive()</code>, <code>add.batch()</code>, <code>add.web.searchAndWait()</code>, <code>update()</code>, <code>delete()</code>, <code>status()</code></small></td>
70
+ </tr>
71
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
72
+ <tr>
73
+ <td>List Sources</td>
74
+ <td><code>sdk.sources.list()</code></td>
75
+ <td><a href="examples/source-list.ts">source-list.ts</a></td>
76
+ </tr>
77
+ <tr>
78
+ <td>Add URL Source</td>
79
+ <td><code>sdk.sources.add.url()</code></td>
80
+ <td><a href="examples/source-add-url.ts">source-add-url.ts</a></td>
81
+ </tr>
82
+ <tr>
83
+ <td>Add Text Source</td>
84
+ <td><code>sdk.sources.add.text()</code></td>
85
+ <td><a href="examples/source-add-text.ts">source-add-text.ts</a></td>
86
+ </tr>
87
+ <tr>
88
+ <td>Add YouTube Source</td>
89
+ <td><code>sdk.sources.add.youtube()</code></td>
90
+ <td><a href="examples/source-add-youtube.ts">source-add-youtube.ts</a></td>
91
+ </tr>
92
+ <tr>
93
+ <td>Add File Source</td>
94
+ <td><code>sdk.sources.add.file()</code></td>
95
+ <td><a href="examples/source-add-file.ts">source-add-file.ts</a></td>
96
+ </tr>
97
+ <tr>
98
+ <td>Add Drive Source</td>
99
+ <td><code>sdk.sources.add.drive()</code></td>
100
+ <td><a href="examples/source-add-drive.ts">source-add-drive.ts</a></td>
101
+ </tr>
102
+ <tr>
103
+ <td>Add Batch Sources</td>
104
+ <td><code>sdk.sources.add.batch()</code></td>
105
+ <td><a href="examples/source-add-batch.ts">source-add-batch.ts</a></td>
106
+ </tr>
107
+ <tr>
108
+ <td>Web Search Source</td>
109
+ <td><code>sdk.sources.add.web.searchAndWait()</code></td>
110
+ <td><a href="examples/source-web-search.ts">source-web-search.ts</a></td>
111
+ </tr>
112
+ <tr>
113
+ <td>Advanced Web Search</td>
114
+ <td><code>sdk.sources.add.web.searchAndWait()</code></td>
115
+ <td><a href="examples/source-web-search-advanced.ts">source-web-search-advanced.ts</a></td>
116
+ </tr>
117
+ <tr>
118
+ <td>Get Source</td>
119
+ <td><code>sdk.sources.get()</code></td>
120
+ <td><a href="examples/source-get.ts">source-get.ts</a></td>
121
+ </tr>
122
+ <tr>
123
+ <td>Update Source</td>
124
+ <td><code>sdk.sources.update()</code></td>
125
+ <td><a href="examples/source-update.ts">source-update.ts</a></td>
126
+ </tr>
127
+ <tr>
128
+ <td>Delete Source</td>
129
+ <td><code>sdk.sources.delete()</code></td>
130
+ <td><a href="examples/source-delete.ts">source-delete.ts</a></td>
131
+ </tr>
132
+ <tr>
133
+ <td>Check Source Status</td>
134
+ <td><code>sdk.sources.status()</code></td>
135
+ <td><a href="examples/source-status.ts">source-status.ts</a></td>
136
+ </tr>
137
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
138
+ <tr>
139
+ <td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#artifacts">Artifact Generation</a></strong> <small><code>create()</code>, <code>list()</code>, <code>get()</code>, <code>download()</code>, <code>rename()</code>, <code>delete()</code>, <code>share()</code></small></td>
140
+ </tr>
141
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
142
+ <tr>
143
+ <td>Create Artifact</td>
144
+ <td><code>sdk.artifacts.create()</code></td>
145
+ <td><a href="examples/artifact-create.ts">artifact-create.ts</a></td>
146
+ </tr>
147
+ <tr>
148
+ <td>Create Artifact (Subservices)</td>
149
+ <td><code>sdk.artifacts.{type}.create()</code></td>
150
+ <td><a href="examples/artifact-create-subservices.ts">artifact-create-subservices.ts</a></td>
151
+ </tr>
152
+ <tr>
153
+ <td>List Artifacts</td>
154
+ <td><code>sdk.artifacts.list()</code></td>
155
+ <td><a href="examples/artifact-list.ts">artifact-list.ts</a></td>
156
+ </tr>
157
+ <tr>
158
+ <td>Get Artifact</td>
159
+ <td><code>sdk.artifacts.get()</code></td>
160
+ <td><a href="examples/artifact-get.ts">artifact-get.ts</a></td>
161
+ </tr>
162
+ <tr>
163
+ <td>Download Artifact</td>
164
+ <td><code>sdk.artifacts.download()</code></td>
165
+ <td><a href="examples/artifact-download.ts">artifact-download.ts</a></td>
166
+ </tr>
167
+ <tr>
168
+ <td>Download Video</td>
169
+ <td><code>sdk.artifacts.download()</code></td>
170
+ <td><a href="examples/artifact-video.ts">artifact-video.ts</a></td>
171
+ </tr>
172
+ <tr>
173
+ <td>Download Slides</td>
174
+ <td><code>sdk.artifacts.download()</code></td>
175
+ <td><a href="examples/slide-download-test.ts">slide-download-test.ts</a></td>
176
+ </tr>
177
+ <tr>
178
+ <td>Rename Artifact</td>
179
+ <td><code>sdk.artifacts.rename()</code></td>
180
+ <td><a href="examples/artifact-rename.ts">artifact-rename.ts</a></td>
181
+ </tr>
182
+ <tr>
183
+ <td>Delete Artifact</td>
184
+ <td><code>sdk.artifacts.delete()</code></td>
185
+ <td><a href="examples/artifact-delete.ts">artifact-delete.ts</a></td>
186
+ </tr>
187
+ <tr>
188
+ <td>Share Artifact</td>
189
+ <td><code>sdk.artifacts.share()</code></td>
190
+ <td><a href="examples/artifact-share.ts">artifact-share.ts</a></td>
191
+ </tr>
192
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
193
+ <tr>
194
+ <td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#generation--chat">Chat & Generation</a></strong> <small><code>chat()</code>, <code>chatStream()</code>, <code>setChatConfig()</code></small></td>
195
+ </tr>
196
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
197
+ <tr>
198
+ <td>Chat</td>
199
+ <td><code>sdk.generation.chat()</code></td>
200
+ <td><a href="examples/chat-basic.ts">chat-basic.ts</a></td>
201
+ </tr>
202
+ <tr>
203
+ <td>Stream Chat</td>
204
+ <td><code>sdk.generation.chatStream()</code></td>
205
+ <td><a href="examples/chat-conversation.ts">chat-conversation.ts</a></td>
206
+ </tr>
207
+ <tr>
208
+ <td>Set Chat Config</td>
209
+ <td><code>sdk.generation.setChatConfig()</code></td>
210
+ <td><a href="examples/generation-set-chat-config.ts">generation-set-chat-config.ts</a></td>
211
+ </tr>
212
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
213
+ <tr>
214
+ <td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#notes">Notes Management</a></strong> <small><code>list()</code>, <code>create()</code>, <code>update()</code>, <code>delete()</code></small></td>
215
+ </tr>
216
+ <tr style="height: 30px;"><td colspan="3"></td></tr>
217
+ <tr>
218
+ <td>List Notes</td>
219
+ <td><code>sdk.notes.list()</code></td>
220
+ <td><a href="examples/note-list.ts">note-list.ts</a></td>
221
+ </tr>
222
+ <tr>
223
+ <td>Create Note</td>
224
+ <td><code>sdk.notes.create()</code></td>
225
+ <td><a href="examples/note-create.ts">note-create.ts</a></td>
226
+ </tr>
227
+ <tr>
228
+ <td>Update Note</td>
229
+ <td><code>sdk.notes.update()</code></td>
230
+ <td><a href="examples/note-update.ts">note-update.ts</a></td>
231
+ </tr>
232
+ <tr>
233
+ <td>Delete Note</td>
234
+ <td><code>sdk.notes.delete()</code></td>
235
+ <td><a href="examples/note-delete.ts">note-delete.ts</a></td>
236
+ </tr>
237
+ </tbody>
238
+ </table>
239
+
240
+ ## Installation
241
+
242
+ ```bash
243
+ npm install notebooklm-kit
244
+ ```
245
+
246
+ **From source:**
247
+ ```bash
248
+ git clone https://github.com/photon-hq/notebooklm-kit.git && cd notebooklm-kit && npm run setup
249
+ ```
250
+
251
+ **Requirements:** Node.js >=18.0.0
252
+
253
+ ## Version
254
+
255
+ Current version: **2.1.1**
256
+
257
+ ## Available Scripts
258
+
259
+ When working with the repository, you can use the following npm scripts:
260
+
261
+ | Script | Description |
262
+ |--------|-------------|
263
+ | `npm install` | Install dependencies and automatically build (runs postinstall) |
264
+ | `npm run setup` | Full setup: install dependencies, Playwright, and build |
265
+ | `npm run build` | Compile TypeScript to JavaScript |
266
+ | `npm run build:dev` | Build only (no reinstall) |
267
+ | `npm run dev` | Watch mode (auto-rebuild on file changes) |
268
+ | `npm run clean` | Remove compiled dist/ directory |
269
+
270
+ <details>
271
+ <summary><strong>Development</strong></summary>
272
+
273
+ **First-time setup:**
274
+ ```bash
275
+ npm run setup
276
+ ```
277
+
278
+ **Build only (no reinstall):**
279
+ ```bash
280
+ npm run build:dev
281
+ ```
282
+
283
+ **Watch mode (auto-rebuild):**
284
+ ```bash
285
+ npm run dev
286
+ ```
287
+
288
+ **Clean build:**
289
+ ```bash
290
+ npm run clean && npm run build
291
+ ```
292
+
293
+ </details>
294
+
295
+ ## Quick Start
296
+
297
+ ### 1. Install the package
298
+
299
+ ```bash
300
+ npm install notebooklm-kit
301
+ ```
302
+
303
+ ### 2. Set up authentication
304
+
305
+ **Auto (browser):** Create `.env` with `GOOGLE_EMAIL` and `GOOGLE_PASSWORD` (no 2FA required)
306
+
307
+ **Manual:** Create `.env` with `NOTEBOOKLM_AUTH_TOKEN` and `NOTEBOOKLM_COOKIES` from browser DevTools (Network → Cookie header, Console → `window.WIZ_global_data.SNlM0e`)
308
+
309
+ ### 3. Use the SDK
310
+
311
+ ```typescript
312
+ import { NotebookLMClient } from 'notebooklm-kit';
313
+ import dotenv from 'dotenv';
314
+
315
+ // Load .env file from project root (automatically detected)
316
+ dotenv.config();
317
+
318
+ async function main() {
319
+ const sdk = new NotebookLMClient({
320
+ // Credentials are automatically loaded from .env file
321
+ // Priority: NOTEBOOKLM_AUTH_TOKEN/NOTEBOOKLM_COOKIES > GOOGLE_EMAIL/GOOGLE_PASSWORD
322
+ });
323
+
324
+ try {
325
+ await sdk.connect();
326
+
327
+ // List notebooks
328
+ const notebooks = await sdk.notebooks.list();
329
+ console.log(`Found ${notebooks.length} notebooks`);
330
+
331
+ // Create a notebook
332
+ const notebook = await sdk.notebooks.create({
333
+ title: 'My Research',
334
+ emoji: '📚',
335
+ });
336
+ console.log(`Created: ${notebook.title}`);
337
+
338
+ } catch (error) {
339
+ console.error('Error:', error);
340
+ } finally {
341
+ sdk.dispose();
342
+ }
343
+ }
344
+
345
+ main();
346
+ ```
347
+
348
+ **Note:** The SDK automatically loads credentials from environment variables. See [SDK Initialization](#sdk-initialization) for all configuration options.
349
+
350
+ ### Running Examples
351
+
352
+ The repository includes working examples in the [`examples/`](examples/) directory. To run them:
353
+
354
+ 1. **Set up your `.env` file** in the project root (see [Authentication](#2-set-up-authentication) above)
355
+ 2. **Run any example** using `tsx`:
356
+ ```bash
357
+ npx tsx examples/notebook-list.ts
358
+ npx tsx examples/chat-basic.ts
359
+ ```
360
+
361
+ **Chat Example Usage:**
362
+ ```bash
363
+ # Interactive mode (prompts for notebook and message)
364
+ npx tsx examples/chat-basic.ts
365
+
366
+ # With notebook ID and message (streaming mode - default)
367
+ npx tsx examples/chat-basic.ts <notebook-id> "What are the key findings?"
368
+
369
+ # Non-streaming mode (get complete response at once)
370
+ npx tsx examples/chat-basic.ts <notebook-id> "What are the key findings?" --no-stream
371
+ ```
372
+
373
+ **Note:** The examples automatically detect and load the `.env` file from the project root, regardless of where you run them from.
374
+
375
+ ## Features
376
+
377
+ ### `sdk.notebooks` - Notebook Management
378
+
379
+ | Feature | Description | Method | Example |
380
+ |---------|-------------|--------|---------|
381
+ | List Notebooks | List all your notebooks (recently viewed) | [`sdk.notebooks.list()`](#list-notebooks) | [notebook-list.ts](examples/notebook-list.ts) |
382
+ | Get Notebook | Get full details of a specific notebook | [`sdk.notebooks.get(notebookId)`](#get-notebook) | [notebook-get.ts](examples/notebook-get.ts) |
383
+ | Create Notebook | Create a new notebook (auto-generates title if empty) | [`sdk.notebooks.create(options)`](#create-notebook) | [notebook-create.ts](examples/notebook-create.ts) |
384
+ | Update Notebook | Update notebook title or emoji | [`sdk.notebooks.update(notebookId, options)`](#update-notebook) | [notebook-update.ts](examples/notebook-update.ts) |
385
+ | Delete Notebook | Delete one or more notebooks | [`sdk.notebooks.delete(notebookIds)`](#delete-notebook) | [notebook-delete.ts](examples/notebook-delete.ts) |
386
+ | Share Notebook | Share notebook with users or enable link sharing | [`sdk.notebooks.share(notebookId, options)`](#share-notebook) | [notebook-share.ts](examples/notebook-share.ts) |
387
+
388
+ ### `sdk.sources` - Source Management
389
+
390
+ | Feature | Description | Method | Example |
391
+ |---------|-------------|--------|---------|
392
+ | List Sources | List all sources in a notebook | [`sdk.sources.list(notebookId)`](#list-sources) | [source-list.ts](examples/source-list.ts) |
393
+ | Get Source | Get one or all sources | [`sdk.sources.get(notebookId, sourceId?)`](#get-source) | [source-get.ts](examples/source-get.ts) |
394
+ | Add URL | Add a source from a web page URL | [`sdk.sources.add.url(notebookId, options)`](#add-url-source) | [source-add-url.ts](examples/source-add-url.ts) |
395
+ | Add Text | Add a source from text content | [`sdk.sources.add.text(notebookId, options)`](#add-text-source) | [source-add-text.ts](examples/source-add-text.ts) |
396
+ | Add File | Add a source from a file (PDF, image, etc.) | [`sdk.sources.add.file(notebookId, options)`](#add-file-source) | [source-add-file.ts](examples/source-add-file.ts) |
397
+ | Add YouTube | Add a YouTube video as a source | [`sdk.sources.add.youtube(notebookId, options)`](#add-youtube-source) | [source-add-youtube.ts](examples/source-add-youtube.ts) |
398
+ | Add Google Drive | Add a Google Drive file as a source | [`sdk.sources.add.drive(notebookId, options)`](#add-google-drive-source) | [source-add-drive.ts](examples/source-add-drive.ts) |
399
+ | Batch Add | Add multiple sources at once | [`sdk.sources.add.batch(notebookId, options)`](#batch-add-sources) | [source-add-batch.ts](examples/source-add-batch.ts) |
400
+ | Web Search (Simple) | Search web and wait for results | [`sdk.sources.add.web.searchAndWait(notebookId, options)`](#web-search-simple) | [source-web-search.ts](examples/source-web-search.ts) |
401
+ | Web Search (Advanced) | Multi-step web search workflow | [`sdk.sources.add.web.search()`](#web-search-advanced) → `getResults()` → `addDiscovered()` | [source-web-search-advanced.ts](examples/source-web-search-advanced.ts) |
402
+ | Update Source | Update source metadata | [`sdk.sources.update(notebookId, sourceId, updates)`](#update-source) | [source-update.ts](examples/source-update.ts) |
403
+ | Delete Source | Delete a source from a notebook | [`sdk.sources.delete(notebookId, sourceId)`](#delete-source) | [source-delete.ts](examples/source-delete.ts) |
404
+ | Check Status | Check source processing status | [`sdk.sources.status(notebookId)`](#check-processing-status) | [source-status.ts](examples/source-status.ts) |
405
+
406
+ ### `sdk.artifacts` - Artifact Management
407
+
408
+ | Feature | Description | Method | Example |
409
+ |---------|-------------|--------|---------|
410
+ | Create Artifact | Create study material (quiz, flashcards, mind map, etc.) | [`sdk.artifacts.create()`](#create-artifact) or `sdk.artifacts.{type}.create()` | [artifact-create.ts](examples/artifact-create.ts)<br>[artifact-create-subservices.ts](examples/artifact-create-subservices.ts) |
411
+ | List Artifacts | List all artifacts in a notebook (with filtering) | [`sdk.artifacts.list()`](#list-artifacts) | [artifact-list.ts](examples/artifact-list.ts) |
412
+ | Get Artifact | Get artifact details (auto-fetches content when ready) | [`sdk.artifacts.get()`](#get-artifact) | [artifact-get.ts](examples/artifact-get.ts) |
413
+ | Download Artifact | Download artifact data to disk (quiz/flashcard JSON, audio file) | [`sdk.artifacts.download()`](#download-artifact) | [artifact-download.ts](examples/artifact-download.ts) |
414
+ | Download Video | Download video artifact as MP4 file | [`sdk.artifacts.download()`](#download-artifact) | [artifact-video.ts](examples/artifact-video.ts) |
415
+ | Download Slides | Download slide deck as PDF or PNG files | [`sdk.artifacts.download()`](#download-artifact) | [slide-download-test.ts](examples/slide-download-test.ts) |
416
+ | Rename Artifact | Rename an artifact | [`sdk.artifacts.rename()`](#rename-artifact) | [artifact-rename.ts](examples/artifact-rename.ts) |
417
+ | Delete Artifact | Delete an artifact | [`sdk.artifacts.delete()`](#delete-artifact) | [artifact-delete.ts](examples/artifact-delete.ts) |
418
+ | Share Artifact | Share artifact/notebook with users or enable link sharing | [`sdk.artifacts.share()`](#share-artifact) | [artifact-share.ts](examples/artifact-share.ts) |
419
+
420
+ ### `sdk.generation` - Generation & Chat
421
+
422
+ | Feature | Description | Method | Example |
423
+ |---------|-------------|--------|---------|
424
+ | Chat (Non-streaming) | Chat with notebook content - returns complete response | [`sdk.generation.chat(notebookId, prompt, options?)`](#chat) | [chat-basic.ts](examples/chat-basic.ts) |
425
+ | Chat Stream | Chat with real-time streaming response chunks | [`sdk.generation.chatStream(notebookId, prompt, options?)`](#chat-stream) | [chat-basic.ts](examples/chat-basic.ts) |
426
+ | Chat Conversation | Multi-turn conversations with history tracking | [`sdk.generation.chat(notebookId, prompt, { conversationHistory })`](#chat) | [chat-conversation.ts](examples/chat-conversation.ts) |
427
+ | Set Chat Config | Configure chat (custom prompt, learning guide, response length) | [`sdk.generation.setChatConfig(notebookId, config)`](#set-chat-configuration) | [generation-set-chat-config.ts](examples/generation-set-chat-config.ts) |
428
+
429
+ ### `sdk.notes` - Notes Management
430
+
431
+ | Feature | Description | Method | Example |
432
+ |---------|-------------|--------|---------|
433
+ | List Notes | List all notes in a notebook | [`sdk.notes.list(notebookId)`](#list-notes) | [note-list.ts](examples/note-list.ts) |
434
+ | Create Note | Create a new note | [`sdk.notes.create(notebookId, options)`](#create-note) | [note-create.ts](examples/note-create.ts) |
435
+ | Update Note | Update a note | [`sdk.notes.update(notebookId, noteId, options)`](#update-note) | [note-update.ts](examples/note-update.ts) |
436
+ | Delete Note | Delete a note | [`sdk.notes.delete(notebookId, noteIds)`](#delete-note) | [note-delete.ts](examples/note-delete.ts) |
437
+
438
+ ## Core Concepts
439
+
440
+ ### SDK Initialization
441
+
442
+ **Methods:** `sdk.connect()` | `sdk.dispose()`
443
+
444
+ **Basic Usage:**
445
+ ```typescript
446
+ import { NotebookLMClient } from 'notebooklm-kit';
447
+ import dotenv from 'dotenv';
448
+
449
+ dotenv.config(); // Load .env from project root
450
+
451
+ const sdk = new NotebookLMClient({
452
+ // Credentials loaded automatically from environment variables:
453
+ // NOTEBOOKLM_AUTH_TOKEN, NOTEBOOKLM_COOKIES
454
+ // or GOOGLE_EMAIL, GOOGLE_PASSWORD
455
+ });
456
+
457
+ try {
458
+ await sdk.connect(); // Initialize SDK, authenticate, start auto-refresh
459
+
460
+ // Now you can use sdk.notebooks, sdk.sources, etc.
461
+ const notebooks = await sdk.notebooks.list();
462
+
463
+ } finally {
464
+ sdk.dispose(); // Always cleanup
465
+ }
466
+ ```
467
+
468
+ **Explicit Credentials:**
469
+ ```typescript
470
+ const sdk = new NotebookLMClient({
471
+ authToken: process.env.NOTEBOOKLM_AUTH_TOKEN!,
472
+ cookies: process.env.NOTEBOOKLM_COOKIES!,
473
+ // or
474
+ auth: {
475
+ email: process.env.GOOGLE_EMAIL!,
476
+ password: process.env.GOOGLE_PASSWORD!,
477
+ },
478
+ });
479
+
480
+ await sdk.connect();
481
+ ```
482
+
483
+ **Enable Debug Mode:**
484
+
485
+ Debug mode provides detailed logging for troubleshooting, API calls, authentication, and internal operations.
486
+
487
+ **Option 1: Environment Variable (Recommended)**
488
+ ```bash
489
+ # In your .env file
490
+ NOTEBOOKLM_DEBUG=true
491
+ ```
492
+
493
+ **Option 2: Config Option**
494
+ ```typescript
495
+ const sdk = new NotebookLMClient({
496
+ debug: true, // Enable debug logging
497
+ // ... other config
498
+ });
499
+
500
+ await sdk.connect();
501
+ ```
502
+
503
+ **Option 3: Development Mode**
504
+ ```bash
505
+ # Automatically enables debug in development
506
+ NODE_ENV=development
507
+ ```
508
+
509
+ **What Debug Mode Logs:**
510
+ - ✅ RPC call details (method names, arguments, responses)
511
+ - ✅ Authentication flow (login steps, credential extraction)
512
+ - ✅ Auto-refresh operations (token refresh attempts, timing)
513
+ - ✅ Streaming responses (chunk processing, parsing)
514
+ - ✅ Error details (full stack traces, API responses)
515
+ - ✅ Response parsing (chunked data processing, validation)
516
+
517
+ **Example Debug Output:**
518
+ ```
519
+ [DEBUG] RPC Call: wXbhsf with args: [null, 1, null, [2]]
520
+ [DEBUG] Response received: 200 OK
521
+ [DEBUG] Parsing chunked response: 3 chunks found
522
+ [DEBUG] Auto-refresh: Token expires in 5 minutes, refreshing now...
523
+ [DEBUG] Authentication: Extracting credentials from browser...
524
+ ```
525
+
526
+ **Disable Debug:**
527
+ ```typescript
528
+ // Explicitly disable (overrides environment variable)
529
+ const sdk = new NotebookLMClient({
530
+ debug: false,
531
+ });
532
+ ```
533
+
534
+ ```bash
535
+ # Or in .env
536
+ NOTEBOOKLM_DEBUG=false
537
+ ```
538
+
539
+ <details>
540
+ <summary><strong>Connection Flow</strong></summary>
541
+
542
+ 1. **Credentials Resolution** (in priority order):
543
+ - Provided in config (`authToken`/`cookies`)
544
+ - Environment variables (`NOTEBOOKLM_AUTH_TOKEN`/`NOTEBOOKLM_COOKIES`)
545
+ - Saved credentials (`credentials.json` in project root) - **reused automatically**
546
+ - Auto-login (if `auth.email`/`auth.password` provided) - **only if no saved credentials**
547
+
548
+ **Note:** Set `FORCE_REAUTH=true` in `.env` to force re-authentication and ignore saved credentials
549
+
550
+ 2. **Initialization:**
551
+ - Creates RPC client with credentials
552
+ - Initializes all services (`notebooks`, `sources`, `artifacts`, etc.)
553
+ - Starts auto-refresh manager (if enabled)
554
+
555
+ 3. **Auto-Refresh:**
556
+ - Begins automatically after `connect()`
557
+ - Runs in background, doesn't block operations
558
+ - Updates credentials and cookies automatically
559
+
560
+ </details>
561
+
562
+ <details>
563
+ <summary><strong>Cleanup</strong></summary>
564
+
565
+ **Always call `dispose()` when done:**
566
+ - Stops auto-refresh background timers
567
+ - Prevents memory leaks
568
+ - Resets client state
569
+ - Required for graceful shutdown
570
+
571
+ ```typescript
572
+ try {
573
+ await sdk.connect();
574
+ // ... use SDK ...
575
+ } finally {
576
+ await sdk.dispose(); // Always cleanup
577
+ }
578
+ ```
579
+
580
+ </details>
581
+
582
+ ### Authentication Overview
583
+
584
+ Authentication is handled automatically when you call `sdk.connect()`. Credentials are resolved in this priority order:
585
+
586
+ 1. Provided in config (`authToken`/`cookies`)
587
+ 2. Environment variables (`NOTEBOOKLM_AUTH_TOKEN`/`NOTEBOOKLM_COOKIES`)
588
+ 3. Saved credentials (`credentials.json` in project root)
589
+ 4. Auto-login (if `auth.email`/`auth.password` provided)
590
+
591
+ See the [Authentication](#authentication) section for detailed setup instructions and all configuration options.
592
+
593
+ ### Quota Limits
594
+
595
+ Reference: [Official Documentation](https://support.google.com/notebooklm/answer/16213268)
596
+
597
+ **Plan Types:** `standard` (default) | `plus` | `pro` | `ultra`
598
+
599
+ | Limit | Standard | Plus | Pro | Ultra |
600
+ |-------|----------|------|-----|-------|
601
+ | **Notebooks** | 100/user | 200/user | 500/user | 500/user |
602
+ | **Sources/Notebook** | 50 | 100 | 300 | 600 |
603
+ | **Words/Source** | 500,000 | 500,000 | 500,000 | 500,000 |
604
+ | **File Size** | 200MB | 200MB | 200MB | 200MB |
605
+ | **Chats/Day** | 50 | 200 | 500 | 5,000 |
606
+ | **Audio/Video/Day** | 3 | 6 | 20 | 200 |
607
+ | **Reports/Day** | 10 | 20 | 100 | 1,000 |
608
+ | **Deep Research/Month** | 10 | 90 | 600 | 6,000 |
609
+ | **Mind Maps** | Unlimited | Unlimited | Unlimited | Unlimited |
610
+
611
+ <details>
612
+ <summary><strong>Important Notes</strong></summary>
613
+
614
+ - **Daily quotas** reset after 24 hours
615
+ - **Monthly quotas** reset after 30 days
616
+ - **Word/File Limits:** NotebookLM rejects sources >500k words or >200MB. Copy-protected PDFs cannot be imported.
617
+ - **Server-Side Enforcement:** Data Tables, Infographics, Slides (limits vary)
618
+ - **Client-Side Validation:** Optional (`enforceQuotas: true`), disabled by default
619
+ - **Plan Selection:** Set during SDK initialization: `plan: 'pro'`
620
+
621
+ </details>
622
+
623
+ ## Authentication
624
+
625
+ ### Auto-Login (Recommended)
626
+
627
+ **Method:** Use `auth` config with email/password
628
+
629
+ ```typescript
630
+ const sdk = new NotebookLMClient({
631
+ auth: {
632
+ email: process.env.GOOGLE_EMAIL,
633
+ password: process.env.GOOGLE_PASSWORD,
634
+ headless: true, // default: true
635
+ },
636
+ });
637
+
638
+ await sdk.connect(); // Logs in, extracts auth token, prompts for cookies, saves to credentials.json
639
+ ```
640
+
641
+ <details>
642
+ <summary><strong>Environment Variables (.env file)</strong></summary>
643
+
644
+ **File Location:** Create `.env` in your **project root** directory (same directory as `package.json`).
645
+
646
+ ```bash
647
+ # .env file location: /path/to/your-project/.env
648
+
649
+ # Option 1: Auto-login with email/password (recommended - requires no 2FA)
650
+ GOOGLE_EMAIL="your-email@gmail.com"
651
+ GOOGLE_PASSWORD="your-password"
652
+
653
+ # Option 2: Manual credentials (for production or when auto-login isn't available)
654
+ NOTEBOOKLM_AUTH_TOKEN="ACi2F2NZSD7yrNvFMrCkP3vZJY1R:1766720233448"
655
+ NOTEBOOKLM_COOKIES="_ga=GA1.1.1949425436.1764104083; SID=g.a0005AiwX...; ..."
656
+
657
+ # Optional: Retry configuration
658
+ NOTEBOOKLM_MAX_RETRIES=1 # Default: 1
659
+ NOTEBOOKLM_RETRY_DELAY=1000 # Default: 1000ms
660
+ NOTEBOOKLM_RETRY_MAX_DELAY=5000 # Default: 5000ms
661
+
662
+ # Optional: Debug mode (enables detailed logging)
663
+ NOTEBOOKLM_DEBUG=true # Enable debug logging for troubleshooting
664
+
665
+ # Optional: Force re-authentication (ignore saved credentials)
666
+ FORCE_REAUTH=true
667
+ ```
668
+
669
+ **Important:**
670
+ - `.env` file must be in the **project root** (not in subdirectories)
671
+ - Account must NOT have 2FA enabled (or use app-specific passwords)
672
+ - The `.env` file is automatically ignored by git (see `.gitignore`)
673
+
674
+ </details>
675
+
676
+ ### Manual Credentials
677
+
678
+ **Method:** Provide `authToken` and `cookies` directly
679
+
680
+ ```typescript
681
+ const sdk = new NotebookLMClient({
682
+ authToken: process.env.NOTEBOOKLM_AUTH_TOKEN!,
683
+ cookies: process.env.NOTEBOOKLM_COOKIES!,
684
+ enforceQuotas: true, // optional
685
+ plan: 'standard', // optional: 'standard' | 'plus' | 'pro' | 'ultra'
686
+ });
687
+
688
+ await sdk.connect();
689
+ ```
690
+
691
+ <details>
692
+ <summary><strong>Getting Credentials</strong></summary>
693
+
694
+ 1. **Auth Token**: Open https://notebooklm.google.com → DevTools (F12) → Console → Run: `window.WIZ_global_data.SNlM0e`
695
+ 2. **Cookies**: DevTools → Network tab → Any request → Headers → Copy Cookie value
696
+
697
+ </details>
698
+
699
+ ### Saved Credentials
700
+
701
+ **Location:** `credentials.json` in project root (e.g., `notebooklm-kit/credentials.json`)
702
+
703
+ When using auto-login with email/password:
704
+ 1. Browser opens and authenticates
705
+ 2. Auth token is extracted automatically
706
+ 3. You're prompted to manually paste cookies
707
+ 4. Credentials are saved to `credentials.json` for future use
708
+
709
+ **Subsequent runs:**
710
+ - Saved credentials are automatically reused (no browser prompt)
711
+ - Faster startup - no need to re-enter cookies
712
+ - Credentials file is in project root for easy viewing/editing
713
+
714
+ **To force re-authentication:**
715
+ - Set `FORCE_REAUTH=true` in `.env`, or
716
+ - Delete `credentials.json` file
717
+
718
+ **Security Note:** `credentials.json` contains sensitive authentication data. It's automatically added to `.gitignore` to prevent accidental commits.
719
+
720
+ ### Auto-Refresh Configuration
721
+
722
+ **Default:** Enabled with `'auto'` strategy (recommended)
723
+
724
+ ```typescriptimproved
725
+ // Default: auto strategy (expiration-based + time-based fallback)
726
+ const sdk = new NotebookLMClient({
727
+ auth: { email: '...', password: '...' },
728
+ // autoRefresh: true (default)
729
+ });
730
+
731
+ // Time-based (simple, predictable)
732
+ autoRefresh: { strategy: 'time', interval: 10 * 60 * 1000 }
733
+
734
+ // Expiration-based (maximum efficiency)
735
+ autoRefresh: { strategy: 'expiration', refreshAhead: 5 * 60 * 1000 }
736
+
737
+ // Disable
738
+ autoRefresh: false
739
+
740
+ // Manual refresh
741
+ await sdk.refreshCredentials();
742
+ ```
743
+
744
+ <details>
745
+ <summary><strong>Auto-Refresh Details</strong></summary>
746
+
747
+ - Credentials updated automatically after refresh
748
+ - Cookies kept in sync
749
+ - Runs in background, doesn't block operations
750
+ - See [Auto-Refresh Strategies](#auto-refresh-strategies) in Core Concepts
751
+
752
+ </details>
753
+
754
+ ### Quota Management
755
+
756
+ **Method:** `sdk.getUsage()` | `sdk.getRemaining()` | `sdk.getQuotaManager()`
757
+
758
+ ```typescript
759
+ const sdk = new NotebookLMClient({
760
+ auth: { email: '...', password: '...' },
761
+ enforceQuotas: true, // Enable client-side validation (disabled by default)
762
+ plan: 'pro', // Set plan for accurate limits
763
+ });
764
+
765
+ await sdk.connect();
766
+
767
+ // Check usage
768
+ const usage = sdk.getUsage();
769
+ const remaining = sdk.getRemaining('chats');
770
+ const limits = sdk.getQuotaManager().getLimits();
771
+ ```
772
+
773
+ <details>
774
+ <summary><strong>Quota Notes</strong></summary>
775
+
776
+ - **Disabled by default** - enable with `enforceQuotas: true`
777
+ - Throws `RateLimitError` if limit exceeded (when enabled)
778
+ - Server-side enforcement always active (even if client-side disabled)
779
+ - See [Quota Limits](#quota-limits) table in Core Concepts
780
+
781
+ </details>
782
+
783
+ ## Notebooks
784
+
785
+ Examples: [notebook-list.ts](examples/notebook-list.ts) | [notebook-get.ts](examples/notebook-get.ts) | [notebook-create.ts](examples/notebook-create.ts) | [notebook-update.ts](examples/notebook-update.ts) | [notebook-delete.ts](examples/notebook-delete.ts) | [notebook-share.ts](examples/notebook-share.ts)
786
+
787
+ ### List Notebooks
788
+
789
+ **Method:** `sdk.notebooks.list()`
790
+
791
+ **Example:** [notebook-list.ts](examples/notebook-list.ts)
792
+
793
+ **Returns:** `Promise<Notebook[]>`
794
+
795
+ **Description:**
796
+ Lists all your notebooks (recently viewed). Returns a lightweight array of notebooks with essential information for display/selection.
797
+
798
+ **Return Fields:**
799
+ - `projectId: string` - Unique notebook ID (required for other operations)
800
+ - `title: string` - Notebook title
801
+ - `emoji: string` - Visual identifier
802
+ - `sourceCount: number` - Number of sources in the notebook
803
+
804
+ <details>
805
+ <summary><strong>Notes</strong></summary>
806
+
807
+ - Automatically filters out system notebooks (e.g., "OpenStax's Biology")
808
+ - Returns only notebooks you've recently viewed
809
+ - Does not include full notebook details (use `get()` for that)
810
+ - Does not include sources array (use `sources` service for source operations)
811
+ - Does not include sharing info (use `get()` for sharing details)
812
+
813
+ </details>
814
+
815
+ **Usage:**
816
+ ```typescript
817
+ const notebooks = await sdk.notebooks.list()
818
+ console.log(`Found ${notebooks.length} notebooks`)
819
+ notebooks.forEach(nb => {
820
+ console.log(`${nb.emoji} ${nb.title} (${nb.sourceCount} sources)`)
821
+ })
822
+ ```
823
+
824
+ ---
825
+
826
+ ### Get Notebook
827
+
828
+ **Method:** `sdk.notebooks.get(notebookId)`
829
+
830
+ **Example:** [notebook-get.ts](examples/notebook-get.ts)
831
+
832
+ **Parameters:**
833
+ - `notebookId: string` - The notebook ID (required)
834
+
835
+ **Returns:** `Promise<Notebook>`
836
+
837
+ **Description:**
838
+ Retrieves full details of a specific notebook, including analytics and sharing information. Makes parallel RPC calls to get complete notebook data.
839
+
840
+ **Return Fields:**
841
+ - `projectId: string` - Unique notebook ID
842
+ - `title: string` - Notebook title
843
+ - `emoji: string` - Visual identifier
844
+ - `sourceCount?: number` - Number of sources (analytics)
845
+ - `lastAccessed?: string` - Last accessed timestamp (ISO format, analytics)
846
+ - `sharing?: SharingSettings` - Sharing configuration:
847
+ - `isShared: boolean` - Whether notebook is shared
848
+ - `shareUrl?: string` - Share URL if shared
849
+ - `shareId?: string` - Share ID
850
+ - `publicAccess?: boolean` - Whether public access is enabled
851
+ - `allowedUsers?: string[]` - Array of user emails with access
852
+
853
+ <details>
854
+ <summary><strong>Notes</strong></summary>
855
+
856
+ - Validates notebook ID format before making RPC calls
857
+ - Calls both `RPC_GET_PROJECT` and `RPC_GET_SHARING_DETAILS` in parallel for efficiency
858
+ - Sharing data is optional - won't fail if unavailable
859
+ - Does not include sources array (use `sources` service for source operations)
860
+ - `lastAccessed` is extracted from notebook metadata if available
861
+
862
+ </details>
863
+
864
+ **Usage:**
865
+ ```typescript
866
+ const notebook = await sdk.notebooks.get('notebook-id')
867
+ console.log(`Title: ${notebook.title}`)
868
+ console.log(`Sources: ${notebook.sourceCount || 0}`)
869
+ console.log(`Last accessed: ${notebook.lastAccessed || 'Never'}`)
870
+ if (notebook.sharing?.isShared) {
871
+ console.log(`Share URL: ${notebook.sharing.shareUrl}`)
872
+ }
873
+ ```
874
+
875
+ ---
876
+
877
+ ### Create Notebook
878
+
879
+ **Method:** `sdk.notebooks.create(options)`
880
+
881
+ **Example:** [notebook-create.ts](examples/notebook-create.ts)
882
+
883
+ **Parameters:**
884
+ - `options: CreateNotebookOptions`
885
+ - `title: string` - Notebook title (optional, auto-generated if empty)
886
+ - `description?: string` - Initial description (optional)
887
+ - `emoji?: string` - Notebook emoji (optional)
888
+
889
+ **Returns:** `Promise<Notebook>`
890
+
891
+ **Description:**
892
+ Creates a new notebook. Automatically generates a title if not provided. Validates title length before creation.
893
+
894
+ **Return Fields:**
895
+ - `projectId: string` - Unique notebook ID (use this for subsequent operations)
896
+ - `title: string` - Notebook title (as provided or auto-generated)
897
+ - `emoji: string` - Default emoji
898
+
899
+ **Auto-Generated Title Format:**
900
+ If `title` is empty or not provided, generates: `"Untitled Notebook {current date}"`
901
+ Example: `"Untitled Notebook 12/30/2024"`
902
+
903
+ <details>
904
+ <summary><strong>Validation</strong></summary>
905
+
906
+ - Title maximum length: 100 characters
907
+ - Throws `APIError` if title exceeds limit
908
+ - Empty title is allowed (will be auto-generated)
909
+
910
+ </details>
911
+
912
+ <details>
913
+ <summary><strong>Notes</strong></summary>
914
+
915
+ - Quota is checked before creation (if quota manager is enabled)
916
+ - Usage is recorded after successful creation
917
+ - Returns immediately with notebook ID - no waiting required
918
+ - Does not include `sourceCount`, `lastAccessed`, or `sharing` (not available for new notebooks)
919
+
920
+ </details>
921
+
922
+ **Usage:**
923
+ ```typescript
924
+ // With title
925
+ const notebook = await sdk.notebooks.create({
926
+ title: 'My Research Project',
927
+ })
928
+
929
+ // With title and emoji
930
+ const notebook = await sdk.notebooks.create({
931
+ title: 'My Research Project',
932
+ emoji: '📚',
933
+ })
934
+
935
+ // Auto-generated title
936
+ const untitled = await sdk.notebooks.create({})
937
+
938
+ // With description and emoji
939
+ const notebook = await sdk.notebooks.create({
940
+ title: 'Project Notes',
941
+ description: 'Initial project description',
942
+ emoji: '🔬',
943
+ })
944
+ ```
945
+
946
+ ---
947
+
948
+ ### Update Notebook
949
+
950
+ **Method:** `sdk.notebooks.update(notebookId, options)`
951
+
952
+ **Example:** [notebook-update.ts](examples/notebook-update.ts)
953
+
954
+ **Parameters:**
955
+ - `notebookId: string` - The notebook ID (required, automatically trimmed)
956
+ - `options: UpdateNotebookOptions`
957
+ - `title?: string` - New title (optional)
958
+ - `emoji?: string` - New emoji (optional)
959
+ - `metadata?: Record<string, any>` - Other metadata updates (optional)
960
+
961
+ **Returns:** `Promise<Notebook>` (same as `get()` - full notebook details)
962
+
963
+ **Description:**
964
+ Updates notebook title, description, or emoji. Returns full notebook details after update (same structure as `get()`). Supports updating emoji only, title only, or both together.
965
+
966
+ <details>
967
+ <summary><strong>Validation</strong></summary>
968
+
969
+ - At least one field (`title`, `description`, or `emoji`) must be provided
970
+ - Title maximum length: 100 characters
971
+ - Notebook ID is automatically trimmed (removes trailing spaces)
972
+ - Returns error if notebook doesn't exist
973
+
974
+ </details>
975
+
976
+ **Return Fields:**
977
+ Same as `get()` - includes `projectId`, `title`, `emoji`, `sourceCount`, `lastAccessed`, `sharing`
978
+
979
+ <details>
980
+ <summary><strong>Notes</strong></summary>
981
+
982
+ - Notebook ID is trimmed automatically to prevent issues with trailing spaces
983
+ - Only provided fields are updated (partial updates supported)
984
+ - Returns full notebook object after update (not just updated fields)
985
+ - Does not validate notebook existence first (for performance) - returns error if not found
986
+
987
+ </details>
988
+
989
+ **Usage:**
990
+ ```typescript
991
+ // Update title only
992
+ const updated = await sdk.notebooks.update('notebook-id', {
993
+ title: 'Updated Title',
994
+ })
995
+
996
+ // Update emoji only
997
+ const updated = await sdk.notebooks.update('notebook-id', {
998
+ emoji: '🔥',
999
+ })
1000
+
1001
+ // Update both title and emoji
1002
+ const updated = await sdk.notebooks.update('notebook-id', {
1003
+ title: 'New Title',
1004
+ emoji: '⭐',
1005
+ })
1006
+
1007
+ // Update all fields
1008
+ const updated = await sdk.notebooks.update('notebook-id', {
1009
+ title: 'New Title',
1010
+ emoji: '🎯',
1011
+ })
1012
+ ```
1013
+
1014
+ ---
1015
+
1016
+ ### Delete Notebook
1017
+
1018
+ **Method:** `sdk.notebooks.delete(notebookIds)`
1019
+
1020
+ **Example:** [notebook-delete.ts](examples/notebook-delete.ts)
1021
+
1022
+ **Parameters:**
1023
+ - `notebookIds: string | string[]` - Single notebook ID or array of IDs (required)
1024
+
1025
+ **Returns:** `Promise<DeleteNotebookResult>`
1026
+
1027
+ **Description:**
1028
+ Deletes one or more notebooks. Returns confirmation with deleted IDs and count.
1029
+
1030
+ **Return Fields:**
1031
+ - `deleted: string[]` - Array of deleted notebook IDs
1032
+ - `count: number` - Number of notebooks deleted
1033
+
1034
+ <details>
1035
+ <summary><strong>Validation</strong></summary>
1036
+
1037
+ - All provided IDs are validated before deletion
1038
+ - Throws `APIError` if any ID is invalid
1039
+ - Supports both single ID and array of IDs
1040
+
1041
+ </details>
1042
+
1043
+ <details>
1044
+ <summary><strong>Notes</strong></summary>
1045
+
1046
+ - No confirmation required - deletion is immediate
1047
+ - Batch deletion is supported (pass array of IDs)
1048
+ - Returns validation/confirmation object (not void)
1049
+ - All IDs are validated before any deletion occurs
1050
+
1051
+ </details>
1052
+
1053
+ **Usage:**
1054
+ ```typescript
1055
+ // Delete single notebook
1056
+ const result = await sdk.notebooks.delete('notebook-id')
1057
+ console.log(`Deleted ${result.count} notebook: ${result.deleted[0]}`)
1058
+
1059
+ // Delete multiple notebooks
1060
+ const result = await sdk.notebooks.delete(['id-1', 'id-2', 'id-3'])
1061
+ console.log(`Deleted ${result.count} notebooks: ${result.deleted.join(', ')}`)
1062
+ ```
1063
+
1064
+ ---
1065
+
1066
+ ### Share Notebook
1067
+
1068
+ **Method:** `sdk.notebooks.share(notebookId, options)`
1069
+
1070
+ **Example:** [notebook-share.ts](examples/notebook-share.ts)
1071
+
1072
+ **Parameters:**
1073
+ - `notebookId: string` - The notebook ID (required, automatically trimmed)
1074
+ - `options: ShareNotebookOptions`
1075
+ - `users?: Array<{email: string, role: 2|3|4}>` - Users to share with (optional)
1076
+ - `notify?: boolean` - Notify users (default: true, only used when users are provided)
1077
+ - `accessType?: 1|2` - Access type: 1=anyone with link, 2=restricted (optional, default: 2)
1078
+
1079
+ **Returns:** `Promise<ShareNotebookResult>`
1080
+
1081
+ **Description:**
1082
+ Shares notebook with users or enables link sharing. Supports multiple users with different roles. Automatically fetches updated sharing state after operation.
1083
+
1084
+ **User Roles:**
1085
+
1086
+ | Role | Value | Description |
1087
+ |------|-------|-------------|
1088
+ | Editor | `2` | Can edit notebook content |
1089
+ | Viewer | `3` | Can view notebook only |
1090
+ | Remove | `4` | Remove user from shared list |
1091
+
1092
+ **Access Types:**
1093
+
1094
+ | Access Type | Value | Description |
1095
+ |-------------|-------|-------------|
1096
+ | Anyone with link | `1` | Public access via share link |
1097
+ | Restricted | `2` | Only specified users can access |
1098
+
1099
+ **Return Fields:**
1100
+ - `shareUrl: string` - Share URL (always present, even if not shared)
1101
+ - `success: boolean` - Whether the share operation succeeded
1102
+ - `notebookId: string` - The notebook ID that was shared
1103
+ - `accessType: 1|2` - Access type: 1=anyone with link, 2=restricted
1104
+ - `isShared: boolean` - Whether the notebook is shared (true if shared with users or link enabled)
1105
+ - `users?: Array<{email: string, role: 2|3}>` - Users with access (only present if users were shared)
1106
+
1107
+ **Notify Behavior:**
1108
+ - `notify` is only used when `users` are provided
1109
+ - Default: `true` (users are notified when permissions change)
1110
+ - Set to `false` to share silently
1111
+ - Not used when only changing link access (no user changes)
1112
+
1113
+ <details>
1114
+ <summary><strong>Validation</strong></summary>
1115
+
1116
+ - Email addresses are validated using regex before sharing
1117
+ - Throws `APIError` if any email is invalid
1118
+ - Supports multiple users in a single call
1119
+
1120
+ </details>
1121
+
1122
+ <details>
1123
+ <summary><strong>Notes</strong></summary>
1124
+ - Notebook ID is automatically trimmed
1125
+ - Makes prerequisite `JFMDGd` call before sharing (to initialize sharing state)
1126
+ - After successful share, makes another `JFMDGd` call to fetch updated state
1127
+ - `shareUrl` is always returned (constructed from notebook ID if not explicitly shared)
1128
+ - Supports sharing with multiple users in a single operation
1129
+ - Can combine user sharing with link access in one call
1130
+
1131
+ </details>
1132
+
1133
+ **Usage:**
1134
+ ```typescript
1135
+ // Share with users (restricted access, notify enabled by default)
1136
+ const result = await sdk.notebooks.share('notebook-id', {
1137
+ users: [
1138
+ { email: 'user1@example.com', role: 2 }, // editor
1139
+ { email: 'user2@example.com', role: 3 }, // viewer
1140
+ ],
1141
+ notify: true,
1142
+ accessType: 2, // restricted
1143
+ })
1144
+
1145
+ // Share with users (silent, no notification)
1146
+ const result = await sdk.notebooks.share('notebook-id', {
1147
+ users: [
1148
+ { email: 'user@example.com', role: 2 },
1149
+ ],
1150
+ notify: false,
1151
+ accessType: 2,
1152
+ })
1153
+
1154
+ // Enable link sharing (anyone with link)
1155
+ const result = await sdk.notebooks.share('notebook-id', {
1156
+ accessType: 1, // 1=anyone with link, 2=restricted
1157
+ })
1158
+
1159
+ // Remove user (role: 4)
1160
+ const result = await sdk.notebooks.share('notebook-id', {
1161
+ users: [
1162
+ { email: 'user@example.com', role: 4 }, // remove
1163
+ ],
1164
+ accessType: 2,
1165
+ })
1166
+ ```
1167
+
1168
+ <details>
1169
+ <summary><b>Sources</b> - Add & manage sources</summary>
1170
+
1171
+ ### Methods
1172
+
1173
+ #### `addFromURL(notebookId: string, options: AddURLSourceOptions)` → `Promise<string>`
1174
+ Add a source from a URL (web page, YouTube, etc.).
1175
+
1176
+ **Parameters:**
1177
+ - `notebookId: string` - The notebook ID
1178
+ - `options.url: string` - URL to add
1179
+
1180
+ **Returns:**
1181
+ - `string` - Source ID
1182
+
1183
+ **Example:**
1184
+ ```typescript
1185
+ const sourceId = await sdk.sources.addFromURL('notebook-id', {
1186
+ url: 'https://example.com/article',
1187
+ })
1188
+ ```
1189
+
1190
+ ---
1191
+
1192
+ #### `addFromText(notebookId: string, options: AddTextSourceOptions)` → `Promise<string>`
1193
+ Add a source from text content.
1194
+
1195
+ **Parameters:**
1196
+ - `notebookId: string` - The notebook ID
1197
+ - `options.title: string` - Source title
1198
+ - `options.content: string` - Text content
1199
+
1200
+ **Returns:**
1201
+ - `string` - Source ID
1202
+
1203
+ **Example:**
1204
+ ```typescript
1205
+ const sourceId = await sdk.sources.addFromText('notebook-id', {
1206
+ title: 'Research Notes',
1207
+ content: 'Your text content here...',
1208
+ })
1209
+ ```
1210
+
1211
+ ---
1212
+
1213
+ #### `addFromFile(notebookId: string, options: AddFileSourceOptions)` → `Promise<string>`
1214
+ Add a source from a file (PDF, image, etc.).
1215
+
1216
+ **Parameters:**
1217
+ - `notebookId: string` - The notebook ID
1218
+ - `options.content: Buffer` - File content as Buffer
1219
+ - `options.fileName: string` - File name
1220
+ - `options.mimeType: string` - MIME type (e.g., 'application/pdf')
1221
+
1222
+ **Returns:**
1223
+ - `string` - Source ID
1224
+
1225
+ **Example:**
1226
+ ```typescript
1227
+ import { readFile } from 'fs/promises'
1228
+
1229
+ const buffer = await readFile('./document.pdf')
1230
+ const sourceId = await sdk.sources.addFromFile('notebook-id', {
1231
+ content: buffer,
1232
+ fileName: 'document.pdf',
1233
+ mimeType: 'application/pdf',
1234
+ })
1235
+ ```
1236
+
1237
+ ---
1238
+
1239
+ #### `addYouTube(notebookId: string, options: AddYouTubeSourceOptions)` → `Promise<string>`
1240
+ Add a YouTube video as a source.
1241
+
1242
+ **Parameters:**
1243
+ - `notebookId: string` - The notebook ID
1244
+ - `options.urlOrId: string` - YouTube URL or video ID
1245
+
1246
+ **Returns:**
1247
+ - `string` - Source ID
1248
+
1249
+ **Example:**
1250
+ ```typescript
1251
+ const sourceId = await sdk.sources.addYouTube('notebook-id', {
1252
+ urlOrId: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
1253
+ })
1254
+ ```
1255
+
1256
+ ---
1257
+
1258
+ #### `searchWebAndWait(notebookId: string, options: SearchWebOptions)` → `Promise<SearchWebResult>`
1259
+ Search the web or Google Drive and wait for results.
1260
+
1261
+ **Parameters:**
1262
+ - `notebookId: string` - The notebook ID
1263
+ - `options.query: string` - Search query
1264
+ - `options.sourceType: SearchSourceType` - WEB or GOOGLE_DRIVE
1265
+ - `options.mode: ResearchMode` - STANDARD or DEEP
1266
+
1267
+ **Returns:**
1268
+ - `SearchWebResult` - Object with:
1269
+ - `sessionId: string` - Session ID for adding sources
1270
+ - `sources: Array<{sourceId: string, title: string, ...}>` - Found sources
1271
+
1272
+ **Example:**
1273
+ ```typescript
1274
+ import { SearchSourceType, ResearchMode } from 'notebooklm-kit'
1275
+
1276
+ const result = await sdk.sources.searchWebAndWait('notebook-id', {
1277
+ query: 'machine learning trends 2024',
1278
+ sourceType: SearchSourceType.WEB,
1279
+ mode: ResearchMode.STANDARD,
1280
+ })
1281
+
1282
+ // Add selected sources
1283
+ const sourceIds = await sdk.sources.addDiscovered('notebook-id', {
1284
+ sessionId: result.sessionId,
1285
+ sourceIds: result.sources.slice(0, 5).map(s => s.sourceId),
1286
+ })
1287
+ ```
1288
+
1289
+ ---
1290
+
1291
+ #### `pollProcessing(notebookId: string)` → `Promise<SourceProcessingStatus>`
1292
+ Check source processing status.
1293
+
1294
+ **Parameters:**
1295
+ - `notebookId: string` - The notebook ID
1296
+
1297
+ **Returns:**
1298
+ - `SourceProcessingStatus` - Object with:
1299
+ - `readyCount: number` - Number of ready sources
1300
+ - `totalCount: number` - Total sources
1301
+ - `processingCount: number` - Sources being processed
1302
+ - `failedCount: number` - Failed sources
1303
+ - `allReady: boolean` - Whether all sources are ready
1304
+
1305
+ **Example:**
1306
+ ```typescript
1307
+ const status = await sdk.sources.pollProcessing('notebook-id')
1308
+ console.log(`Ready: ${status.readyCount}/${status.totalCount}`)
1309
+ ```
1310
+
1311
+ </details>
1312
+
1313
+ ## Sources
1314
+
1315
+ Examples: [source-list.ts](examples/source-list.ts) | [source-get.ts](examples/source-get.ts) | [source-add-url.ts](examples/source-add-url.ts) | [source-add-text.ts](examples/source-add-text.ts) | [source-add-file.ts](examples/source-add-file.ts) | [source-add-youtube.ts](examples/source-add-youtube.ts) | [source-add-drive.ts](examples/source-add-drive.ts) | [source-add-batch.ts](examples/source-add-batch.ts) | [source-web-search.ts](examples/source-web-search.ts) | [source-web-search-advanced.ts](examples/source-web-search-advanced.ts) | [source-update.ts](examples/source-update.ts) | [source-delete.ts](examples/source-delete.ts) | [source-status.ts](examples/source-status.ts)
1316
+
1317
+ ### List Sources
1318
+
1319
+ **Method:** `sdk.sources.list(notebookId)`
1320
+
1321
+ **Example:** [source-list.ts](examples/source-list.ts)
1322
+
1323
+ **Parameters:**
1324
+ - `notebookId: string` - The notebook ID (required)
1325
+
1326
+ **Returns:** `Promise<Source[]>`
1327
+
1328
+ **Description:**
1329
+ Retrieves a list of all sources (URLs, text, files, YouTube videos, Google Drive files, etc.) associated with a notebook. Sources are extracted from the notebook response efficiently without requiring a separate RPC call.
1330
+
1331
+ **Return Fields:**
1332
+ - `sourceId: string` - Unique identifier for the source
1333
+ - `title?: string` - Source title/name
1334
+ - `type?: SourceType` - Source type (URL, TEXT, PDF, YOUTUBE_VIDEO, GOOGLE_DRIVE, IMAGE, etc.)
1335
+ - `url?: string` - Source URL (for URL/YouTube sources)
1336
+ - `createdAt?: string` - Creation timestamp (ISO format)
1337
+ - `updatedAt?: string` - Last modified timestamp (ISO format)
1338
+ - `status?: SourceStatus` - Processing status (`PROCESSING`, `READY`, `FAILED`)
1339
+ - `metadata?: Record<string, any>` - Additional metadata (file size, MIME type, etc.)
1340
+
1341
+ **Source Types:**
1342
+ - `URL` - Web page URL
1343
+ - `TEXT` - Text content
1344
+ - `PDF` - PDF file
1345
+ - `YOUTUBE_VIDEO` - YouTube video
1346
+ - `GOOGLE_DRIVE` - Google Drive file
1347
+ - `IMAGE` - Image file
1348
+ - `VIDEO_FILE` - Video file upload
1349
+ - `PDF_FROM_DRIVE` - PDF from Google Drive
1350
+ - `TEXT_NOTE` - Text note
1351
+ - `MIND_MAP_NOTE` - Mind map note
1352
+
1353
+ <details>
1354
+ <summary><strong>Notes</strong></summary>
1355
+
1356
+ - Sources are extracted from the notebook response (same RPC as `notebooks.get()`)
1357
+ - Processing status is inferred from source metadata
1358
+ - Returns empty array if notebook has no sources
1359
+ - File size and MIME type are included in metadata when available
1360
+
1361
+ </details>
1362
+
1363
+ **Usage:**
1364
+ ```typescript
1365
+ // List all sources
1366
+ const sources = await sdk.sources.list('notebook-id')
1367
+ console.log(`Found ${sources.length} sources`)
1368
+
1369
+ // Filter by type
1370
+ const pdfs = sources.filter(s => s.type === SourceType.PDF)
1371
+ const urls = sources.filter(s => s.type === SourceType.URL)
1372
+
1373
+ // Check processing status
1374
+ const ready = sources.filter(s => s.status === SourceStatus.READY)
1375
+ const processing = sources.filter(s => s.status === SourceStatus.PROCESSING)
1376
+ ```
1377
+
1378
+ ---
1379
+
1380
+ ### Get Source
1381
+
1382
+ **Method:** `sdk.sources.get(notebookId, sourceId?)`
1383
+
1384
+ **Example:** [source-get.ts](examples/source-get.ts)
1385
+
1386
+ **Parameters:**
1387
+ - `notebookId: string` - The notebook ID (required)
1388
+ - `sourceId?: string` - Optional source ID to get a single source
1389
+
1390
+ **Returns:** `Promise<Source | Source[]>` - Single source if `sourceId` provided, array of all sources if omitted
1391
+
1392
+ **Description:**
1393
+ Get one or all sources from a notebook. If `sourceId` is provided, returns a single source. If omitted, returns all sources (same as `list()`).
1394
+
1395
+ **Return Fields:**
1396
+ Same as `list()` - see [List Sources](#list-sources) for field descriptions.
1397
+
1398
+ <details>
1399
+ <summary><strong>Notes</strong></summary>
1400
+
1401
+ - Returns array if `sourceId` is omitted (same as `list()`)
1402
+ - Returns single source object if `sourceId` is provided
1403
+ - Throws error if source not found when `sourceId` is provided
1404
+ - Efficiently reuses notebook data (no separate RPC call)
1405
+
1406
+ </details>
1407
+
1408
+ **Usage:**
1409
+ ```typescript
1410
+ // Get all sources
1411
+ const allSources = await sdk.sources.get('notebook-id')
1412
+
1413
+ // Get specific source
1414
+ const source = await sdk.sources.get('notebook-id', 'source-id')
1415
+ console.log(source.title)
1416
+ ```
1417
+
1418
+ ---
1419
+
1420
+ ### Add URL Source
1421
+
1422
+ **Method:** `sdk.sources.add.url(notebookId, options)`
1423
+
1424
+ **Example:** [source-add-url.ts](examples/source-add-url.ts)
1425
+
1426
+ **Parameters:**
1427
+ - `notebookId: string` - The notebook ID (required)
1428
+ - `options: AddSourceFromURLOptions`
1429
+ - `url: string` - URL to add (required)
1430
+ - `title?: string` - Optional custom title
1431
+
1432
+ **Returns:** `Promise<string>` - Source ID
1433
+
1434
+ **Description:**
1435
+ Adds a web page URL as a source. Returns immediately after source is queued. Use `status()` to check if source is ready.
1436
+
1437
+ <details>
1438
+ <summary><strong>Notes</strong></summary>
1439
+
1440
+ - Returns immediately after source is queued (does not wait for processing)
1441
+ - Quota is checked before adding
1442
+ - Use `status()` to check if source is ready
1443
+ - URL must be a valid HTTP/HTTPS URL
1444
+
1445
+ </details>
1446
+
1447
+ **Usage:**
1448
+ ```typescript
1449
+ const sourceId = await sdk.sources.add.url('notebook-id', {
1450
+ url: 'https://ai.google.dev/',
1451
+ title: 'Google AI Developer',
1452
+ })
1453
+
1454
+ // Check if ready
1455
+ const status = await sdk.sources.status('notebook-id')
1456
+ if (!status.processing.includes(sourceId)) {
1457
+ console.log('Source is ready!')
1458
+ }
1459
+ ```
1460
+
1461
+ ---
1462
+
1463
+ ### Add Text Source
1464
+
1465
+ **Method:** `sdk.sources.add.text(notebookId, options)`
1466
+
1467
+ **Example:** [source-add-text.ts](examples/source-add-text.ts)
1468
+
1469
+ **Parameters:**
1470
+ - `notebookId: string` - The notebook ID (required)
1471
+ - `options: AddSourceFromTextOptions`
1472
+ - `content: string` - Text content (required)
1473
+ - `title: string` - Source title (required)
1474
+
1475
+ **Returns:** `Promise<string>` - Source ID
1476
+
1477
+ **Description:**
1478
+ Adds text content as a source. Useful for adding notes, research summaries, or any text-based content.
1479
+
1480
+ **Usage:**
1481
+ ```typescript
1482
+ const sourceId = await sdk.sources.add.text('notebook-id', {
1483
+ title: 'Research Notes',
1484
+ content: 'Key findings from research...',
1485
+ })
1486
+ ```
1487
+
1488
+ ---
1489
+
1490
+ ### Add File Source
1491
+
1492
+ **Method:** `sdk.sources.add.file(notebookId, options)`
1493
+
1494
+ **Parameters:**
1495
+ - `notebookId: string` - The notebook ID (required)
1496
+ - `options: AddSourceFromFileOptions`
1497
+ - `content: Buffer | string` - File content as Buffer or base64 string (required)
1498
+ - `fileName: string` - File name (required)
1499
+ - `mimeType?: string` - MIME type (optional, auto-detected if not provided)
1500
+
1501
+ **Returns:** `Promise<string>` - Source ID
1502
+
1503
+ **Description:**
1504
+ Adds a file (PDF, image, video, etc.) as a source. Supports files as Buffer or base64 string.
1505
+
1506
+ **Supported File Types:**
1507
+ - PDF files
1508
+ - Image files (PNG, JPG, etc.)
1509
+ - Video files
1510
+ - Other document types
1511
+
1512
+ **Usage:**
1513
+ ```typescript
1514
+ import fs from 'fs'
1515
+
1516
+ // From file buffer
1517
+ const fileBuffer = fs.readFileSync('document.pdf')
1518
+ const sourceId = await sdk.sources.add.file('notebook-id', {
1519
+ content: fileBuffer,
1520
+ fileName: 'document.pdf',
1521
+ mimeType: 'application/pdf',
1522
+ })
1523
+
1524
+ // From base64 string
1525
+ const base64Content = fileBuffer.toString('base64')
1526
+ const sourceId = await sdk.sources.add.file('notebook-id', {
1527
+ content: base64Content,
1528
+ fileName: 'document.pdf',
1529
+ })
1530
+ ```
1531
+
1532
+ ---
1533
+
1534
+ ### Add YouTube Source
1535
+
1536
+ **Method:** `sdk.sources.add.youtube(notebookId, options)`
1537
+
1538
+ **Example:** [source-add-youtube.ts](examples/source-add-youtube.ts)
1539
+
1540
+ **Parameters:**
1541
+ - `notebookId: string` - The notebook ID (required)
1542
+ - `options: AddYouTubeSourceOptions`
1543
+ - `urlOrId: string` - YouTube URL or video ID (required)
1544
+ - `title?: string` - Optional custom title
1545
+
1546
+ **Returns:** `Promise<string>` - Source ID
1547
+
1548
+ **Description:**
1549
+ Adds a YouTube video as a source. Accepts either full YouTube URL or just the video ID.
1550
+
1551
+ **Usage:**
1552
+ ```typescript
1553
+ // From YouTube URL
1554
+ const sourceId = await sdk.sources.add.youtube('notebook-id', {
1555
+ urlOrId: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
1556
+ })
1557
+
1558
+ // From video ID
1559
+ const sourceId = await sdk.sources.add.youtube('notebook-id', {
1560
+ urlOrId: 'dQw4w9WgXcQ',
1561
+ })
1562
+ ```
1563
+
1564
+ ---
1565
+
1566
+ ### Add Google Drive Source
1567
+
1568
+ **Method:** `sdk.sources.add.drive(notebookId, options)`
1569
+
1570
+ **Parameters:**
1571
+ - `notebookId: string` - The notebook ID (required)
1572
+ - `options: AddGoogleDriveSourceOptions`
1573
+ - `fileId: string` - Google Drive file ID (required)
1574
+ - `title?: string` - Optional custom title
1575
+ - `mimeType?: string` - MIME type (optional, inferred if not provided)
1576
+
1577
+ **Returns:** `Promise<string>` - Source ID
1578
+
1579
+ **Description:**
1580
+ Adds a Google Drive file as a source. Requires the file ID from Google Drive.
1581
+
1582
+ <details>
1583
+ <summary><strong>Deprecated</strong></summary>
1584
+
1585
+ This method is deprecated. Use `add.batch()` with `type: 'gdrive'` instead.
1586
+
1587
+ </details>
1588
+
1589
+ **Usage:**
1590
+ ```typescript
1591
+ const sourceId = await sdk.sources.add.drive('notebook-id', {
1592
+ fileId: '1a2b3c4d5e6f7g8h9i0j',
1593
+ mimeType: 'application/vnd.google-apps.document',
1594
+ title: 'My Document',
1595
+ })
1596
+ ```
1597
+
1598
+ ---
1599
+
1600
+ ### Batch Add Sources
1601
+
1602
+ **Method:** `sdk.sources.add.batch(notebookId, options)`
1603
+
1604
+ **Example:** [source-add-batch.ts](examples/source-add-batch.ts)
1605
+
1606
+ **Parameters:**
1607
+ - `notebookId: string` - The notebook ID (required)
1608
+ - `options: BatchAddSourcesOptions`
1609
+ - `sources: Array<...>` - Array of source inputs (required)
1610
+ - `waitForProcessing?: boolean` - Whether to wait for all sources to be processed (default: false)
1611
+ - `timeout?: number` - Timeout in ms if `waitForProcessing` is true (default: 300000 = 5 minutes)
1612
+ - `pollInterval?: number` - Poll interval in ms (default: 2000 = 2 seconds)
1613
+ - `onProgress?: (ready: number, total: number) => void` - Progress callback
1614
+
1615
+ **Returns:** `Promise<string[]>` - Array of source IDs
1616
+
1617
+ **Description:**
1618
+ Adds multiple sources at once. Supports mixed source types (URLs, text, files, YouTube, Google Drive) in a single call.
1619
+
1620
+ **Source Types:**
1621
+ - `{ type: 'url', url: string, title?: string }` - URL source
1622
+ - `{ type: 'text', title: string, content: string }` - Text source
1623
+ - `{ type: 'file', content: Buffer | string, fileName: string, mimeType?: string }` - File source
1624
+ - `{ type: 'youtube', urlOrId: string, title?: string }` - YouTube source
1625
+ - `{ type: 'gdrive', fileId: string, title?: string, mimeType?: string }` - Google Drive source
1626
+
1627
+ **Usage:**
1628
+ ```typescript
1629
+ const sourceIds = await sdk.sources.add.batch('notebook-id', {
1630
+ sources: [
1631
+ { type: 'url', url: 'https://example.com', title: 'Example' },
1632
+ { type: 'text', title: 'Notes', content: 'Content here...' },
1633
+ { type: 'youtube', urlOrId: 'dQw4w9WgXcQ' },
1634
+ ],
1635
+ waitForProcessing: true, // Optional: wait for all to be ready
1636
+ timeout: 300000, // 5 minutes
1637
+ onProgress: (ready, total) => {
1638
+ console.log(`Progress: ${ready}/${total}`)
1639
+ },
1640
+ })
1641
+ ```
1642
+
1643
+ ---
1644
+
1645
+ ### Web Search (Simple)
1646
+
1647
+ **Method:** `sdk.sources.add.web.searchAndWait(notebookId, options)`
1648
+
1649
+ **Example:** [source-web-search.ts](examples/source-web-search.ts)
1650
+
1651
+ **Parameters:**
1652
+ - `notebookId: string` - The notebook ID (required)
1653
+ - `options: SearchWebAndWaitOptions`
1654
+ - `query: string` - Search query (required)
1655
+ - `sourceType?: SearchSourceType` - Source type: `WEB` (default) or `GOOGLE_DRIVE`
1656
+ - `mode?: ResearchMode` - Research mode: `FAST` (default) or `DEEP` (web only)
1657
+ - `timeout?: number` - Max wait time in ms (default: 60000 = 60 seconds)
1658
+ - `pollInterval?: number` - Poll interval in ms (default: 2000 = 2 seconds)
1659
+ - `onProgress?: (status) => void` - Progress callback
1660
+
1661
+ **Returns:** `Promise<WebSearchResult>` - Results with `sessionId`, `web` sources, and `drive` sources
1662
+
1663
+ **Description:**
1664
+ **RECOMMENDED FOR SIMPLE WORKFLOWS** - One call that searches and waits for results automatically. Returns all discovered sources once available (or timeout). Perfect for automated workflows where you don't need to see intermediate steps.
1665
+
1666
+ **Research Modes:**
1667
+ - `ResearchMode.FAST` - Quick search (~10-30 seconds, default)
1668
+ - `ResearchMode.DEEP` - Comprehensive research (~60-120 seconds, web only)
1669
+
1670
+ **Source Types:**
1671
+ - `SearchSourceType.WEB` - Search web (default)
1672
+ - `SearchSourceType.GOOGLE_DRIVE` - Search Google Drive (FAST mode only)
1673
+
1674
+ **Return Fields:**
1675
+ - `sessionId: string` - Required for adding sources (use with `addDiscovered()`)
1676
+ - `web: DiscoveredWebSource[]` - Discovered web sources
1677
+ - `drive: DiscoveredDriveSource[]` - Discovered Google Drive sources
1678
+
1679
+ <details>
1680
+ <summary><strong>Notes</strong></summary>
1681
+
1682
+ - Automatically polls for results until available or timeout
1683
+ - Returns results once count stabilizes (assumes search complete)
1684
+ - Progress callback shows result count as search progresses
1685
+ - Use returned `sessionId` with `addDiscovered()` to add selected sources
1686
+
1687
+ </details>
1688
+
1689
+ **Usage:**
1690
+ ```typescript
1691
+ import { ResearchMode, SearchSourceType } from 'notebooklm-kit'
1692
+
1693
+ // Simple search and wait
1694
+ const result = await sdk.sources.add.web.searchAndWait('notebook-id', {
1695
+ query: 'machine learning research papers 2024',
1696
+ mode: ResearchMode.DEEP, // Comprehensive search
1697
+ sourceType: SearchSourceType.WEB,
1698
+ timeout: 120000, // Wait up to 2 minutes
1699
+ onProgress: (status) => {
1700
+ console.log(`Found ${status.resultCount} results so far...`)
1701
+ },
1702
+ })
1703
+
1704
+ console.log(`Found ${result.web.length} web sources`)
1705
+ console.log(`Session ID: ${result.sessionId}`)
1706
+
1707
+ // Add selected sources
1708
+ const addedIds = await sdk.sources.add.web.addDiscovered('notebook-id', {
1709
+ sessionId: result.sessionId,
1710
+ webSources: result.web.slice(0, 5), // Top 5
1711
+ })
1712
+ ```
1713
+
1714
+ ---
1715
+
1716
+ ### Web Search (Advanced)
1717
+
1718
+ **Method:** `sdk.sources.add.web.search(notebookId, options)` → `sdk.sources.add.web.getResults(notebookId, sessionId)` → `sdk.sources.add.web.addDiscovered(notebookId, options)`
1719
+
1720
+ **Example:** [source-web-search-advanced.ts](examples/source-web-search-advanced.ts)
1721
+
1722
+ **Description:**
1723
+ **MULTI-STEP WORKFLOW** - For cases where you want to see results and make decisions at each step. Returns intermediate results so you can validate, filter, or select before adding sources.
1724
+
1725
+ **Workflow Steps:**
1726
+ 1. **`search()`** - Start search, returns `sessionId` immediately
1727
+ 2. **`getResults(sessionId)`** - Get discovered sources (can call multiple times to poll)
1728
+ 3. **`addDiscovered(sessionId, selectedSources)`** - Add your selected sources
1729
+
1730
+ **Step 1: Start Search**
1731
+
1732
+ **Method:** `sdk.sources.add.web.search(notebookId, options)`
1733
+
1734
+ **Parameters:**
1735
+ - `notebookId: string` - The notebook ID (required)
1736
+ - `options: SearchWebSourcesOptions`
1737
+ - `query: string` - Search query (required)
1738
+ - `sourceType?: SearchSourceType` - `WEB` (default) or `GOOGLE_DRIVE`
1739
+ - `mode?: ResearchMode` - `FAST` (default) or `DEEP` (web only)
1740
+
1741
+ **Returns:** `Promise<string>` - Session ID (required for steps 2 and 3)
1742
+
1743
+ **Step 2: Get Results**
1744
+
1745
+ **Method:** `sdk.sources.add.web.getResults(notebookId, sessionId?)`
1746
+
1747
+ **Parameters:**
1748
+ - `notebookId: string` - The notebook ID (required)
1749
+ - `sessionId?: string` - Session ID from step 1 (optional - if omitted, returns all results)
1750
+
1751
+ **Returns:** `Promise<{ web: DiscoveredWebSource[], drive: DiscoveredDriveSource[] }>`
1752
+
1753
+ **Step 3: Add Discovered Sources**
1754
+
1755
+ **Method:** `sdk.sources.add.web.addDiscovered(notebookId, options)`
1756
+
1757
+ **Parameters:**
1758
+ - `notebookId: string` - The notebook ID (required)
1759
+ - `options: AddDiscoveredSourcesOptions`
1760
+ - `sessionId: string` - Session ID from step 1 (required)
1761
+ - `webSources?: DiscoveredWebSource[]` - Web sources to add
1762
+ - `driveSources?: DiscoveredDriveSource[]` - Drive sources to add
1763
+
1764
+ **Returns:** `Promise<string[]>` - Array of added source IDs
1765
+
1766
+ **Usage:**
1767
+ ```typescript
1768
+ // Step 1: Start search
1769
+ const sessionId = await sdk.sources.add.web.search('notebook-id', {
1770
+ query: 'quantum computing',
1771
+ mode: ResearchMode.FAST,
1772
+ })
1773
+
1774
+ // Step 2: Poll for results (you control when/how often)
1775
+ let results
1776
+ do {
1777
+ await new Promise(r => setTimeout(r, 2000)) // Wait 2 seconds
1778
+ results = await sdk.sources.add.web.getResults('notebook-id', sessionId)
1779
+ console.log(`Found ${results.web.length} sources...`)
1780
+ } while (results.web.length === 0)
1781
+
1782
+ // Step 3: Filter and add selected sources
1783
+ const relevant = results.web.filter(s => s.url.includes('arxiv.org'))
1784
+ const addedIds = await sdk.sources.add.web.addDiscovered('notebook-id', {
1785
+ sessionId,
1786
+ webSources: relevant,
1787
+ })
1788
+ ```
1789
+
1790
+ ---
1791
+
1792
+ ### Get Search Results
1793
+
1794
+ **Method:** `sdk.sources.add.web.getResults(notebookId, sessionId?)`
1795
+
1796
+ **Parameters:**
1797
+ - `notebookId: string` - The notebook ID (required)
1798
+ - `sessionId?: string` - Optional session ID to filter results
1799
+
1800
+ **Returns:** `Promise<{ web: DiscoveredWebSource[], drive: DiscoveredDriveSource[] }>`
1801
+
1802
+ **Description:**
1803
+ Returns discovered sources from search sessions. If `sessionId` is provided, filters results to that specific session. If omitted, returns all results (may include results from other searches).
1804
+
1805
+ **Usage:**
1806
+ ```typescript
1807
+ // Get results for specific session
1808
+ const results = await sdk.sources.add.web.getResults('notebook-id', sessionId)
1809
+
1810
+ // Get all results (no filtering)
1811
+ const allResults = await sdk.sources.add.web.getResults('notebook-id')
1812
+ ```
1813
+
1814
+ ---
1815
+
1816
+ ### Add Discovered Sources
1817
+
1818
+ **Method:** `sdk.sources.add.web.addDiscovered(notebookId, options)`
1819
+
1820
+ **Parameters:**
1821
+ - `notebookId: string` - The notebook ID (required)
1822
+ - `options: AddDiscoveredSourcesOptions`
1823
+ - `sessionId: string` - Session ID from search (required)
1824
+ - `webSources?: DiscoveredWebSource[]` - Web sources to add
1825
+ - `driveSources?: DiscoveredDriveSource[]` - Drive sources to add
1826
+
1827
+ **Returns:** `Promise<string[]>` - Array of added source IDs
1828
+
1829
+ **Description:**
1830
+ Adds selected discovered sources from search results. You decide which sources to add (from `getResults()` or `searchAndWait()`).
1831
+
1832
+ **Usage:**
1833
+ ```typescript
1834
+ // After searchAndWait()
1835
+ const result = await sdk.sources.add.web.searchAndWait(...)
1836
+ const addedIds = await sdk.sources.add.web.addDiscovered('notebook-id', {
1837
+ sessionId: result.sessionId,
1838
+ webSources: result.web.slice(0, 5), // Top 5
1839
+ })
1840
+
1841
+ // After manual search workflow
1842
+ const addedIds = await sdk.sources.add.web.addDiscovered('notebook-id', {
1843
+ sessionId: sessionId,
1844
+ webSources: filteredSources,
1845
+ driveSources: selectedDriveSources,
1846
+ })
1847
+ ```
1848
+
1849
+ ---
1850
+
1851
+ ### Update Source
1852
+
1853
+ **Method:** `sdk.sources.update(notebookId, sourceId, updates)`
1854
+
1855
+ **Parameters:**
1856
+ - `notebookId: string` - The notebook ID (required)
1857
+ - `sourceId: string` - The source ID (required)
1858
+ - `updates: Partial<Source>` - Fields to update
1859
+ - `title?: string` - New title
1860
+
1861
+ **Returns:** `Promise<void>`
1862
+
1863
+ **Description:**
1864
+ Updates source metadata. Currently supports updating the title.
1865
+
1866
+ **Usage:**
1867
+ ```typescript
1868
+ await sdk.sources.update('notebook-id', 'source-id', {
1869
+ title: 'Updated Source Title',
1870
+ })
1871
+ ```
1872
+
1873
+ ---
1874
+
1875
+ ### Delete Source
1876
+
1877
+ **Method:** `sdk.sources.delete(notebookId, sourceId)`
1878
+
1879
+ **Example:** [source-delete.ts](examples/source-delete.ts)
1880
+
1881
+ **Parameters:**
1882
+ - `notebookId: string` - The notebook ID (required)
1883
+ - `sourceId: string` - The source ID (required)
1884
+
1885
+ **Returns:** `Promise<void>`
1886
+
1887
+ **Description:**
1888
+ Deletes a source from a notebook.
1889
+
1890
+ **Usage:**
1891
+ ```typescript
1892
+ await sdk.sources.delete('notebook-id', 'source-id')
1893
+ ```
1894
+
1895
+ ---
1896
+
1897
+ ### Check Processing Status
1898
+
1899
+ **Method:** `sdk.sources.status(notebookId)`
1900
+
1901
+ **Example:** [source-status.ts](examples/source-status.ts)
1902
+
1903
+ **Parameters:**
1904
+ - `notebookId: string` - The notebook ID (required)
1905
+
1906
+ **Returns:** `Promise<SourceProcessingStatus>`
1907
+
1908
+ **Description:**
1909
+ Checks the processing status of all sources in a notebook. Returns information about which sources are still processing and whether all sources are ready.
1910
+
1911
+ **Return Fields:**
1912
+ - `allReady: boolean` - Whether all sources are ready
1913
+ - `processing: string[]` - Array of source IDs still processing
1914
+
1915
+ **Usage:**
1916
+ ```typescript
1917
+ const status = await sdk.sources.status('notebook-id')
1918
+
1919
+ if (status.allReady) {
1920
+ console.log('All sources are ready!')
1921
+ } else {
1922
+ console.log(`Still processing: ${status.processing.length} sources`)
1923
+ console.log('Processing IDs:', status.processing)
1924
+ }
1925
+ ```
1926
+
1927
+ ---
1928
+
1929
+ ## Artifacts
1930
+
1931
+ Examples: [artifact-create.ts](examples/artifact-create.ts) | [artifact-create-subservices.ts](examples/artifact-create-subservices.ts) | [artifact-list.ts](examples/artifact-list.ts) | [artifact-get.ts](examples/artifact-get.ts) | [artifact-download.ts](examples/artifact-download.ts) | [artifact-video.ts](examples/artifact-video.ts) | [slide-download-test.ts](examples/slide-download-test.ts) | [artifact-rename.ts](examples/artifact-rename.ts) | [artifact-delete.ts](examples/artifact-delete.ts) | [artifact-share.ts](examples/artifact-share.ts)
1932
+
1933
+ ### Create Artifact
1934
+
1935
+ **Method:** `sdk.artifacts.create(notebookId, type, options)` or `sdk.artifacts.{type}.create(notebookId, options)`
1936
+
1937
+ **Examples:**
1938
+ - [artifact-create.ts](examples/artifact-create.ts) - Using main `create()` method
1939
+ - [artifact-create-subservices.ts](examples/artifact-create-subservices.ts) - Using type-safe sub-service methods
1940
+
1941
+ **Parameters:**
1942
+ - `notebookId: string` - The notebook ID (required)
1943
+ - `type: ArtifactType` - Artifact type (required for main method)
1944
+ - `options: CreateArtifactOptions`
1945
+ - `title?: string` - Artifact title (optional)
1946
+ - `instructions?: string` - Instructions for generation (optional)
1947
+ - `sourceIds?: string[]` - Source IDs to use (optional - automatically uses all sources if omitted)
1948
+ - `customization?: object` - Type-specific customization options (optional)
1949
+
1950
+ **Returns:** `Promise<Artifact>` (or `Promise<VideoOverview>` / `Promise<AudioOverview>` for video/audio)
1951
+
1952
+ **Description:**
1953
+ Creates a study material artifact (quiz, flashcards, report, mind map, infographic, slide deck, audio, video). Supports customization options for 6 out of 8 artifact types. Returns immediately with artifact metadata - check `state` field to see if artifact is ready.
1954
+
1955
+ **Artifact Types:**
1956
+
1957
+ | Type | Value | Customization | Sub-Service |
1958
+ |------|-------|---------------|-------------|
1959
+ | Quiz | `ArtifactType.QUIZ` | ✅ Yes | `sdk.artifacts.quiz.create()` |
1960
+ | Flashcards | `ArtifactType.FLASHCARDS` | ✅ Yes | `sdk.artifacts.flashcard.create()` |
1961
+ | Report | `ArtifactType.REPORT` | ❌ No | `sdk.artifacts.report.create()` |
1962
+ | Mind Map | `ArtifactType.MIND_MAP` | ❌ No | `sdk.artifacts.mindmap.create()` |
1963
+ | Infographic | `ArtifactType.INFOGRAPHIC` | ✅ Yes | `sdk.artifacts.infographic.create()` |
1964
+ | Slide Deck | `ArtifactType.SLIDE_DECK` | ✅ Yes | `sdk.artifacts.slide.create()` |
1965
+ | Audio | `ArtifactType.AUDIO` | ✅ Yes | `sdk.artifacts.audio.create()` |
1966
+ | Video | `ArtifactType.VIDEO` | ✅ Yes | `sdk.artifacts.video.create()` |
1967
+
1968
+ **Customization Options:**
1969
+
1970
+ <details>
1971
+ <summary><strong>Quiz Customization</strong></summary>
1972
+
1973
+ | Option | Values | Description | Default |
1974
+ |-------|--------|-------------|---------|
1975
+ | `numberOfQuestions` | `1`, `2`, `3` | **1** = Fewer (5-10 questions), **2** = Standard (10-15 questions), **3** = More (15-20+ questions) | `2` |
1976
+ | `difficulty` | `1`, `2`, `3` | **1** = Easy (basic recall), **2** = Medium (application), **3** = Hard (analysis/synthesis) | `2` |
1977
+ | `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
1978
+
1979
+ **Example:**
1980
+ ```typescript
1981
+ customization: {
1982
+ numberOfQuestions: 2, // Standard (10-15 questions)
1983
+ difficulty: 2, // Medium difficulty
1984
+ language: NotebookLMLanguage.ENGLISH,
1985
+ }
1986
+ ```
1987
+
1988
+ </details>
1989
+
1990
+ <details>
1991
+ <summary><strong>Flashcard Customization</strong></summary>
1992
+
1993
+ | Option | Values | Description | Default |
1994
+ |-------|--------|-------------|---------|
1995
+ | `numberOfCards` | `1`, `2`, `3` | **1** = Fewer (10-15 cards), **2** = Standard (15-25 cards), **3** = More (25-40+ cards) | `2` |
1996
+ | `difficulty` | `1`, `2`, `3` | **1** = Easy (basic terms), **2** = Medium (concepts), **3** = Hard (complex relationships) | `2` |
1997
+ | `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
1998
+
1999
+ **Example:**
2000
+ ```typescript
2001
+ customization: {
2002
+ numberOfCards: 3, // More cards (25-40+)
2003
+ difficulty: 1, // Easy (basic terms)
2004
+ language: NotebookLMLanguage.ENGLISH,
2005
+ }
2006
+ ```
2007
+
2008
+ </details>
2009
+
2010
+ <details>
2011
+ <summary><strong>Slide Deck Customization</strong></summary>
2012
+
2013
+ | Option | Values | Description | Default |
2014
+ |-------|--------|-------------|---------|
2015
+ | `format` | `2`, `3` | **2** = Presenter slides (concise, bullet points), **3** = Detailed deck (comprehensive, full content) | `2` |
2016
+ | `length` | `1`, `2` | **1** = Short (5-10 slides), **2** = Default (10-15 slides) | `2` |
2017
+ | `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
2018
+
2019
+ **Example:**
2020
+ ```typescript
2021
+ customization: {
2022
+ format: 2, // Presenter slides (concise)
2023
+ length: 2, // Default (10-15 slides)
2024
+ language: NotebookLMLanguage.ENGLISH,
2025
+ }
2026
+ ```
2027
+
2028
+ </details>
2029
+
2030
+ <details>
2031
+ <summary><strong>Infographic Customization</strong></summary>
2032
+
2033
+ | Option | Values | Description | Default |
2034
+ |-------|--------|-------------|---------|
2035
+ | `orientation` | `1`, `2`, `3` | **1** = Landscape (wide format), **2** = Portrait (tall format), **3** = Square (1:1 aspect ratio) | `1` |
2036
+ | `levelOfDetail` | `1`, `2`, `3` | **1** = Concise (key points only), **2** = Standard (balanced detail), **3** = Detailed (comprehensive information) | `2` |
2037
+ | `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
2038
+
2039
+ **Example:**
2040
+ ```typescript
2041
+ customization: {
2042
+ orientation: 1, // Landscape (wide format)
2043
+ levelOfDetail: 2, // Standard detail
2044
+ language: NotebookLMLanguage.ENGLISH,
2045
+ }
2046
+ ```
2047
+
2048
+ </details>
2049
+
2050
+ <details>
2051
+ <summary><strong>Audio Customization</strong></summary>
2052
+
2053
+ | Option | Values | Description | Default |
2054
+ |-------|--------|-------------|---------|
2055
+ | `format` | `0`, `1`, `2`, `3` | **0** = Deep dive (comprehensive analysis), **1** = Brief (quick summary), **2** = Critique (critical analysis), **3** = Debate (multiple perspectives) | `0` |
2056
+ | `length` | `1`, `2`, `3` | **1** = Short (2-5 minutes), **2** = Default (5-10 minutes), **3** = Long (10-15+ minutes) | `2` |
2057
+ | `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
2058
+
2059
+ **Note:** If `sourceIds` is omitted, all sources in the notebook are automatically used.
2060
+
2061
+ **Example:**
2062
+ ```typescript
2063
+ customization: {
2064
+ format: 0, // Deep dive (comprehensive analysis)
2065
+ length: 2, // Default (5-10 minutes)
2066
+ language: NotebookLMLanguage.ENGLISH,
2067
+ }
2068
+ ```
2069
+
2070
+ </details>
2071
+
2072
+ <details>
2073
+ <summary><strong>Video Customization</strong></summary>
2074
+
2075
+ | Option | Values | Description | Default |
2076
+ |-------|--------|-------------|---------|
2077
+ | `format` | `1`, `2` | **1** = Explainer (comprehensive explanation), **2** = Brief (quick overview) | `1` |
2078
+ | `visualStyle` | `0-10` | Visual style for the video (see table below) | `0` |
2079
+ | `focus` | `string` | What should the AI hosts focus on? (optional, e.g., "Key concepts and main findings") | - |
2080
+ | `customStyleDescription` | `string` | Custom visual style description (required when `visualStyle=1`) | - |
2081
+ | `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
2082
+
2083
+ **Visual Style Options:**
2084
+
2085
+ | Value | Style Name | Description |
2086
+ |-------|------------|-------------|
2087
+ | `0` | Auto-select | AI chooses the best style automatically (default) |
2088
+ | `1` | Custom | Requires `customStyleDescription` - describe your desired style |
2089
+ | `2` | Classic | Traditional, professional style |
2090
+ | `3` | Whiteboard | Hand-drawn whiteboard style |
2091
+ | `4` | Kawaii | Cute, colorful style |
2092
+ | `5` | Anime | Anime-inspired style |
2093
+ | `6` | Watercolour | Watercolor painting style |
2094
+ | `7` | Anime (alternative) | Alternative anime style |
2095
+ | `8` | Retro print | Vintage print/poster style |
2096
+ | `9` | Heritage | Traditional ink-wash/woodcut style |
2097
+ | `10` | Paper-craft | Layered paper cutout style |
2098
+
2099
+ **Note:**
2100
+ - All styles except Custom (`1`) support only the `focus` option
2101
+ - Custom (`1`) additionally requires `customStyleDescription`
2102
+ - If `sourceIds` is omitted, all sources in the notebook are automatically used
2103
+
2104
+ **Example:**
2105
+ ```typescript
2106
+ // Auto-select style
2107
+ customization: {
2108
+ format: 1, // Explainer
2109
+ visualStyle: 0, // Auto-select (AI chooses)
2110
+ focus: 'Key concepts and main findings',
2111
+ language: NotebookLMLanguage.ENGLISH,
2112
+ }
2113
+
2114
+ // Custom style
2115
+ customization: {
2116
+ format: 1, // Explainer
2117
+ visualStyle: 1, // Custom
2118
+ customStyleDescription: 'Modern minimalist design with blue and white colors',
2119
+ focus: 'Key concepts and main findings',
2120
+ language: NotebookLMLanguage.ENGLISH,
2121
+ }
2122
+
2123
+ // Specific style (e.g., Whiteboard)
2124
+ customization: {
2125
+ format: 1, // Explainer
2126
+ visualStyle: 3, // Whiteboard style
2127
+ focus: 'Step-by-step explanation of the process',
2128
+ language: NotebookLMLanguage.ENGLISH,
2129
+ }
2130
+ ```
2131
+
2132
+ </details>
2133
+
2134
+ <details>
2135
+ <summary><strong>Report & Mind Map (No Customization)</strong></summary>
2136
+
2137
+ **Report** and **Mind Map** artifacts do not support customization options. They only support:
2138
+ - `title?: string` - Artifact title (optional)
2139
+ - `instructions?: string` - Custom instructions for generation (optional)
2140
+ - `sourceIds?: string[]` - Source IDs to use (optional - automatically uses all sources if omitted)
2141
+
2142
+ **Example:**
2143
+ ```typescript
2144
+ // Create report
2145
+ const report = await sdk.artifacts.report.create('notebook-id', {
2146
+ title: 'Research Report',
2147
+ instructions: 'Create a comprehensive research report',
2148
+ sourceIds: ['source-id-1', 'source-id-2'], // Optional
2149
+ })
2150
+
2151
+ // Create mind map
2152
+ const mindMap = await sdk.artifacts.mindmap.create('notebook-id', {
2153
+ title: 'Concept Map',
2154
+ instructions: 'Create a visual mind map of key concepts',
2155
+ sourceIds: ['source-id-1'], // Optional
2156
+ })
2157
+ ```
2158
+
2159
+ </details>
2160
+
2161
+ **Source Selection:**
2162
+
2163
+ - `sourceIds` is **optional** for all artifact types
2164
+ - If omitted or empty, **all sources** in the notebook are automatically used
2165
+ - If provided, only the specified sources are used
2166
+
2167
+ **Return Fields:**
2168
+ - `artifactId: string` - Unique artifact ID (required for other operations)
2169
+ - `type: ArtifactType` - Artifact type
2170
+ - `state: ArtifactState` - Current state: `CREATING`, `READY`, or `FAILED`
2171
+ - `title: string` - Artifact title
2172
+ - `sourceIds?: string[]` - Source IDs used to create the artifact
2173
+ - `createdAt?: string` - Creation timestamp
2174
+ - `updatedAt?: string` - Last update timestamp
2175
+
2176
+ <details>
2177
+ <summary><strong>Notes</strong></summary>
2178
+
2179
+ - Artifacts are created asynchronously - check `state` field to see if ready
2180
+ - Use `get(artifactId)` to fetch full artifact data when `state === READY`
2181
+ - Quota is checked before creation (if quota manager is enabled)
2182
+ - Usage is recorded after successful creation
2183
+ - Audio and video artifacts return `AudioOverview` / `VideoOverview` instead of `Artifact`
2184
+ - Sub-services provide type-safe convenience methods (e.g., `sdk.artifacts.quiz.create()`)
2185
+
2186
+ </details>
2187
+
2188
+ **Usage:**
2189
+ ```typescript
2190
+ import { ArtifactType } from 'notebooklm-kit'
2191
+
2192
+ // Generic create method
2193
+ const quiz = await sdk.artifacts.create('notebook-id', ArtifactType.QUIZ, {
2194
+ title: 'Chapter 1 Quiz',
2195
+ instructions: 'Create questions covering key concepts',
2196
+ customization: {
2197
+ numberOfQuestions: 2, // Standard
2198
+ difficulty: 2, // Medium
2199
+ language: 'en',
2200
+ },
2201
+ })
2202
+
2203
+ // Using sub-services (type-safe)
2204
+ const quiz = await sdk.artifacts.quiz.create('notebook-id', {
2205
+ title: 'Chapter 1 Quiz',
2206
+ instructions: 'Create questions covering key concepts',
2207
+ customization: {
2208
+ numberOfQuestions: 2,
2209
+ difficulty: 2,
2210
+ language: 'en',
2211
+ },
2212
+ })
2213
+
2214
+ const flashcards = await sdk.artifacts.flashcard.create('notebook-id', {
2215
+ customization: {
2216
+ numberOfCards: 3, // More cards
2217
+ difficulty: 1, // Easy
2218
+ },
2219
+ })
2220
+
2221
+ const video = await sdk.artifacts.video.create('notebook-id', {
2222
+ instructions: 'Create a summary video',
2223
+ customization: {
2224
+ format: 1,
2225
+ visualStyle: 0,
2226
+ language: 'en',
2227
+ },
2228
+ })
2229
+
2230
+ // Check if ready
2231
+ if (quiz.state === ArtifactState.READY) {
2232
+ const fullQuiz = await sdk.artifacts.get(quiz.artifactId, 'notebook-id')
2233
+ }
2234
+ ```
2235
+
2236
+ ---
2237
+
2238
+ ### List Artifacts
2239
+
2240
+ **Method:** `sdk.artifacts.list(notebookId, options?)`
2241
+
2242
+ **Example:** [artifact-list.ts](examples/artifact-list.ts)
2243
+
2244
+ **Parameters:**
2245
+ - `notebookId: string` - The notebook ID (required)
2246
+ - `options?: { type?: ArtifactType; state?: ArtifactState }` - Filtering options (optional)
2247
+
2248
+ **Returns:** `Promise<Artifact[]>`
2249
+
2250
+ **Description:**
2251
+ Lists all artifacts in a notebook. Supports filtering by type and/or state. Returns lightweight artifact metadata for display/selection.
2252
+
2253
+ **Return Fields:**
2254
+ - `artifactId: string` - Unique artifact ID
2255
+ - `type: ArtifactType` - Artifact type
2256
+ - `state: ArtifactState` - Current state (`CREATING`, `READY`, `FAILED`)
2257
+ - `title: string` - Artifact title
2258
+ - `sourceIds?: string[]` - Source IDs used
2259
+ - `createdAt?: string` - Creation timestamp
2260
+ - `updatedAt?: string` - Last update timestamp
2261
+
2262
+ <details>
2263
+ <summary><strong>Notes</strong></summary>
2264
+
2265
+ - Returns all artifact types (quiz, flashcards, report, mind map, infographic, slide deck, audio, video)
2266
+ - Filtering is optional - returns all artifacts if no filters provided
2267
+ - Does not include full artifact content (use `get()` for that)
2268
+ - Check `state` field to see if artifacts are ready before fetching content
2269
+
2270
+ </details>
2271
+
2272
+ **Usage:**
2273
+ ```typescript
2274
+ import { ArtifactType, ArtifactState } from 'notebooklm-kit'
2275
+
2276
+ // List all artifacts
2277
+ const artifacts = await sdk.artifacts.list('notebook-id')
2278
+ console.log(`Found ${artifacts.length} artifacts`)
2279
+
2280
+ // Filter by type
2281
+ const quizzes = await sdk.artifacts.list('notebook-id', {
2282
+ type: ArtifactType.QUIZ,
2283
+ })
2284
+
2285
+ // Filter by state
2286
+ const ready = await sdk.artifacts.list('notebook-id', {
2287
+ state: ArtifactState.READY,
2288
+ })
2289
+
2290
+ // Filter by both type and state
2291
+ const readyQuizzes = await sdk.artifacts.list('notebook-id', {
2292
+ type: ArtifactType.QUIZ,
2293
+ state: ArtifactState.READY,
2294
+ })
2295
+
2296
+ // Display artifacts
2297
+ artifacts.forEach(artifact => {
2298
+ console.log(`${artifact.title} (${artifact.type}) - ${artifact.state}`)
2299
+ })
2300
+ ```
2301
+
2302
+ ---
2303
+
2304
+ ### Get Artifact
2305
+
2306
+ **Method:** `sdk.artifacts.get(artifactId, notebookId?, options?)`
2307
+
2308
+ **Examples:** [artifact-get.ts](examples/artifact-get.ts) | [artifact-video.ts](examples/artifact-video.ts) (video-specific) | [slide-download-test.ts](examples/slide-download-test.ts) (slide-specific)
2309
+
2310
+ **Parameters:**
2311
+ - `artifactId: string` - The artifact ID from `create()` or `list()` (required)
2312
+ - `notebookId?: string` - Optional notebook ID (helpful for audio/video if get() needs it)
2313
+ - `options?: { exportToDocs?: boolean; exportToSheets?: boolean }` - Export options (for reports only)
2314
+
2315
+ **Returns:** `Promise<Artifact | QuizData | FlashcardData | AudioArtifact | VideoArtifact | any>`
2316
+
2317
+ **Description:**
2318
+ Retrieves detailed artifact information. Automatically fetches full content when artifact is `READY`:
2319
+ - **Quiz/Flashcards**: Returns full data (questions, flashcards array, CSV)
2320
+ - **Audio**: Returns audio metadata (use `download()` to get audio file)
2321
+ - **Video**: Returns video URL in `videoData` field (use `download()` to download video file)
2322
+ - **Slides**: Returns slide image URLs (use `download()` to download slides as PDF/PNG)
2323
+ - **Reports**: Returns basic metadata (use `download()` to get report content, or `get()` with export options for Google Docs/Sheets)
2324
+ - **Infographics**: Returns image data with dimensions
2325
+ - **Mind Maps**: Returns with `experimental: true` flag
2326
+
2327
+ **Return Types by Artifact Type:**
2328
+
2329
+ | Type | Returns | Content |
2330
+ |------|---------|---------|
2331
+ | Quiz | `QuizData` | Questions, options, correct answers, explanations |
2332
+ | Flashcards | `FlashcardData` | Flashcards array, CSV, totalCards |
2333
+ | Audio | `AudioArtifact` | Audio metadata (use `download()` for audio file) |
2334
+ | Video | `Artifact` | Video URL in `videoData` field (use `download()` to download) |
2335
+ | Slides | `Artifact` | Slide image URLs in `slideUrls` array (use `download()` to download) |
2336
+ | Report | `Artifact` | Basic metadata (artifactId, notebookId, state, title) - use `download()` for content or export options |
2337
+ | Infographic | `InfographicImageData` | Image data, dimensions, URL |
2338
+ | Mind Map | `Artifact` | Metadata with `experimental: true` |
2339
+
2340
+ **Important Notes:**
2341
+ - **Videos & Slides**: `get()` returns URLs/links only, not downloaded files. Use `download()` method to actually download files.
2342
+ - **Reports**: `get()` returns basic metadata only. Use `download()` to get report content, or use export options below.
2343
+ - **Audio**: `get()` may not include audio data. Use `download()` to get the audio file.
2344
+
2345
+ **Report Export Options:**
2346
+ - `exportToDocs?: boolean` - Export to Google Docs and return export URL
2347
+ - `exportToSheets?: boolean` - Export to Google Sheets and return export URL
2348
+ - If neither provided, returns basic artifact metadata only (use `download()` for content)
2349
+
2350
+ <details>
2351
+ <summary><strong>Validation</strong></summary>
2352
+
2353
+ - Export options (`exportToDocs`, `exportToSheets`) can only be used with `REPORT` artifacts
2354
+ - Throws error if export options are used on non-report artifacts
2355
+ - `notebookId` is required for audio artifacts (must match `artifactId`)
2356
+
2357
+ </details>
2358
+
2359
+ <details>
2360
+ <summary><strong>Notes</strong></summary>
2361
+
2362
+ - Automatically detects artifact type and fetches appropriate content
2363
+ - For `READY` artifacts, returns full data instead of just metadata
2364
+ - For `CREATING` or `FAILED` artifacts, returns metadata only
2365
+ - **Videos & Slides**: Returns URLs only (use `download()` to download files)
2366
+ - **Reports**: Returns basic metadata only (use `download()` for content or export options)
2367
+ - Quiz and flashcards return full structured data
2368
+ - Audio may not include audio data in `get()` - use `download()` to get audio file
2369
+
2370
+ </details>
2371
+
2372
+ **Usage:**
2373
+ ```typescript
2374
+ import { ArtifactType, ArtifactState } from 'notebooklm-kit'
2375
+
2376
+ // Get quiz with full data
2377
+ const quiz = await sdk.artifacts.get('quiz-id', 'notebook-id')
2378
+ if (quiz.state === ArtifactState.READY) {
2379
+ console.log(`Quiz: ${quiz.title}`)
2380
+ console.log(`Questions: ${quiz.questions?.length || 0}`)
2381
+ quiz.questions?.forEach((q, i) => {
2382
+ console.log(`Q${i + 1}: ${q.question}`)
2383
+ })
2384
+ }
2385
+
2386
+ // Get flashcards with full data
2387
+ const flashcards = await sdk.artifacts.get('flashcard-id', 'notebook-id')
2388
+ if (flashcards.state === ArtifactState.READY) {
2389
+ console.log(`Total cards: ${flashcards.totalCards}`)
2390
+ flashcards.flashcards?.forEach(card => {
2391
+ console.log(`Q: ${card.question} | A: ${card.answer}`)
2392
+ })
2393
+ }
2394
+
2395
+ // Get video URL (use download() to download file)
2396
+ const video = await sdk.artifacts.get('video-id', 'notebook-id')
2397
+ console.log(`Video URL: ${video.videoData}`)
2398
+ // To download: await sdk.artifacts.download('video-id', './downloads', 'notebook-id')
2399
+
2400
+ // Get slide URLs (use download() to download files)
2401
+ const slides = await sdk.artifacts.get('slide-id', 'notebook-id')
2402
+ console.log(`Slide URLs: ${slides.slideUrls?.length || 0} slides`)
2403
+ slides.slideUrls?.forEach((url, i) => {
2404
+ console.log(`Slide ${i + 1}: ${url}`)
2405
+ })
2406
+ // To download: await sdk.artifacts.download('slide-id', './downloads', 'notebook-id')
2407
+
2408
+ // Get report metadata (use download() for content or export options)
2409
+ const report = await sdk.artifacts.get('report-id', 'notebook-id')
2410
+ console.log(`Report: ${report.title} (${report.state})`)
2411
+ // To get content: await sdk.artifacts.download('report-id', './downloads', 'notebook-id')
2412
+
2413
+ // Export report to Google Docs
2414
+ const report = await sdk.artifacts.get('report-id', 'notebook-id', {
2415
+ exportToDocs: true,
2416
+ })
2417
+ console.log(`Docs URL: ${report.exportUrl}`)
2418
+
2419
+ // Export report to Google Sheets
2420
+ const report = await sdk.artifacts.get('report-id', 'notebook-id', {
2421
+ exportToSheets: true,
2422
+ })
2423
+ console.log(`Sheets URL: ${report.exportUrl}`)
2424
+
2425
+ // Get audio metadata (use download() to get audio file)
2426
+ const audioArtifact = await sdk.artifacts.audio.create('notebook-id')
2427
+ const audio = await sdk.artifacts.get(audioArtifact.audioId, 'notebook-id')
2428
+ console.log(`Audio: ${audio.title} (${audio.state})`)
2429
+ // To download: await sdk.artifacts.download(audioArtifact.audioId, './downloads', 'notebook-id')
2430
+ ```
2431
+
2432
+ ---
2433
+
2434
+ ### Download Artifact
2435
+
2436
+ **Method:** `sdk.artifacts.download(artifactId, folderPath, notebookId?)`
2437
+
2438
+ **Example:** [artifact-download.ts](examples/artifact-download.ts)
2439
+
2440
+ **Parameters:**
2441
+ - `artifactId: string` - The artifact ID from `create()` or `list()` (required)
2442
+ - `folderPath: string` - Output folder path (required)
2443
+ - `notebookId?: string` - Optional notebook ID (helpful for audio/video if download needs it)
2444
+
2445
+ **Returns:** `Promise<{ filePath: string; data: any }>`
2446
+
2447
+ **Description:**
2448
+ Downloads artifact content and saves to disk. Automatically determines file format and saves with appropriate filename.
2449
+
2450
+ **Supported Artifacts:**
2451
+
2452
+ | Type | Format | Filename | Content |
2453
+ |------|--------|----------|---------|
2454
+ | Quiz | JSON | `quiz_{artifactId}_{timestamp}.json` | Complete quiz data with questions, options, answers, explanations |
2455
+ | Flashcards | JSON | `flashcard_{artifactId}_{timestamp}.json` | Complete flashcard data with array, CSV, totalCards |
2456
+ | Audio | Audio file | `audio_{artifactId}.mp3` | Audio file (binary) |
2457
+ | Video | MP4 file | `<artifact-title>.mp4` | Video downloaded as MP4 using Playwright |
2458
+ | Slides | PDF file | `<artifact-title>.pdf` or `<artifact-title>/slide_*.png` | Slides downloaded as PDF (default) or PNG files using Playwright |
2459
+
2460
+ <details>
2461
+ <summary><strong>Notes</strong></summary>
2462
+
2463
+ - Quiz and flashcards are saved as JSON files with complete data
2464
+ - Audio is saved as binary file (format depends on backend)
2465
+ - Video and slides are downloaded using Playwright for authentication
2466
+ - Videos are downloaded as MP4 files
2467
+ - Slides are downloaded as PDF (default) or PNG files
2468
+ - For PDF downloads, `pdf-lib` package is recommended (falls back to PNG if not available)
2469
+ - PNG files are saved in a subfolder named after the artifact
2470
+ - Files are saved with timestamps to avoid overwrites (except for slides which use artifact title)
2471
+ - Returns both file path and parsed data (for quiz/flashcards)
2472
+
2473
+ </details>
2474
+
2475
+ **Usage:**
2476
+ ```typescript
2477
+ // Download quiz
2478
+ const result = await sdk.artifacts.download('quiz-id', './downloads', 'notebook-id')
2479
+ console.log(`Saved to: ${result.filePath}`)
2480
+ console.log(`Questions: ${result.data.questions?.length || 0}`)
2481
+
2482
+ // Download flashcards
2483
+ const result = await sdk.artifacts.download('flashcard-id', './downloads', 'notebook-id')
2484
+ console.log(`Saved to: ${result.filePath}`)
2485
+ console.log(`Total cards: ${result.data.totalCards}`)
2486
+
2487
+ // Download audio (use audioId from create() or list())
2488
+ const audio = await sdk.artifacts.audio.create('notebook-id')
2489
+ const result = await sdk.artifacts.download(audio.audioId, './downloads', 'notebook-id')
2490
+ console.log(`Audio saved to: ${result.filePath}`)
2491
+
2492
+ // Download video (use download() method)
2493
+ const result = await sdk.artifacts.download('video-id', './downloads', 'notebook-id')
2494
+ console.log(`Video saved to: ${result.filePath}`)
2495
+
2496
+ // Download slides (use download() method)
2497
+ const slidesResult = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id')
2498
+ console.log(`Slides saved to: ${slidesResult.filePath}`)
2499
+
2500
+ // Download report (use download() method)
2501
+ const reportResult = await sdk.artifacts.download('report-id', './downloads', 'notebook-id')
2502
+ console.log(`Report saved to: ${reportResult.filePath}`)
2503
+ ```
2504
+
2505
+ ---
2506
+
2507
+ ### Download Video
2508
+
2509
+ **Method:** `sdk.artifacts.download(videoId, outputPath, notebookId)`
2510
+
2511
+ **Example:** [artifact-video.ts](examples/artifact-video.ts)
2512
+
2513
+ **Parameters:**
2514
+ - `videoId` (string, required): The video artifact ID
2515
+ - `outputPath` (string, required): Directory path to save the downloaded video
2516
+ - `notebookId` (string, required): The notebook ID containing the video
2517
+
2518
+ **Returns:** `{ filePath: string, data: Artifact }` - File path and artifact data
2519
+
2520
+ **Description:**
2521
+ Downloads a video artifact as an MP4 file. Uses Playwright for authentication and Node's native http/https for reliable download with real-time progress tracking. The video file is saved with the artifact title as the filename.
2522
+
2523
+ **Important Notes:**
2524
+ - **Use `get()` to get video URL**: `get()` returns the video URL in `videoData` field, not a downloaded file
2525
+ - **Use `download()` to download**: `download()` method downloads the video file to disk
2526
+ - Video must be in `READY` state before downloading (check with `get()` first)
2527
+ - Requires `GOOGLE_EMAIL` and `GOOGLE_PASSWORD` environment variables for authentication
2528
+ - Uses Playwright for authentication and Node's http/https for reliable streaming download
2529
+ - Shows real-time download progress (percentage and progress bar)
2530
+ - Video is saved as `<artifact-title>.mp4` in the specified output directory
2531
+
2532
+ **Usage:**
2533
+ ```typescript
2534
+ // Get video URL (get() returns URL only)
2535
+ const video = await sdk.artifacts.get('video-id', 'notebook-id')
2536
+ console.log(`Video URL: ${video.videoData}`)
2537
+
2538
+ // Download video (download() saves file to disk)
2539
+ const result = await sdk.artifacts.download('video-id', './downloads', 'notebook-id')
2540
+ console.log(`Video saved to: ${result.filePath}`)
2541
+ ```
2542
+
2543
+ **Example Workflow:**
2544
+ ```typescript
2545
+ // 1. Check video status and get URL
2546
+ const video = await sdk.artifacts.get('video-id', 'notebook-id')
2547
+ console.log(`Video URL: ${video.videoData}`)
2548
+ if (video.state === ArtifactState.READY) {
2549
+ // 2. Download video
2550
+ const downloaded = await sdk.artifacts.download('video-id', './downloads', 'notebook-id')
2551
+ console.log(`Downloaded: ${downloaded.filePath}`)
2552
+ }
2553
+ ```
2554
+
2555
+ ---
2556
+
2557
+ ### Download Slides
2558
+
2559
+ **Method:** `sdk.artifacts.download(slideId, outputPath, notebookId, { downloadAs })`
2560
+
2561
+ **Example:** [slide-download-test.ts](examples/slide-download-test.ts)
2562
+
2563
+ **Interactive Example (`slide-download-test.ts`):**
2564
+
2565
+ The `slide-download-test.ts` example provides an interactive script for downloading slide decks:
2566
+
2567
+ 1. **Lists and selects notebooks** - Shows all available notebooks and prompts for selection
2568
+ 2. **Lists and selects slide artifacts** - Displays all ready slide deck artifacts for the selected notebook
2569
+ 3. **Extracts slide image URLs** - Recursively searches artifact data structure to find slide image URLs
2570
+ 4. **Authenticates with Google** - Uses Playwright to authenticate with Google (handles 2FA)
2571
+ 5. **Downloads images** - Downloads each slide image using authenticated browser session
2572
+ 6. **Saves in requested format** - Saves as PNG (individual files) or PDF (single file)
2573
+
2574
+ **Environment Variables for `slide-download-test.ts`:**
2575
+ - `NOTEBOOK_ID` - Optional: Pre-select a notebook ID (skips notebook selection)
2576
+ - `GOOGLE_EMAIL` - Required: Google account email for authentication
2577
+ - `GOOGLE_PASSWORD` - Required: Google account password for authentication
2578
+ - `DOWNLOAD_AS` - Optional: `'pdf'` or `'png'` (defaults to interactive prompt)
2579
+ - `OUTPUT_DIR` - Optional: Output directory path (defaults to `./downloads`)
2580
+
2581
+ **Usage:**
2582
+ ```bash
2583
+ # Using tsx (recommended)
2584
+ NOTEBOOK_ID=your-notebook-id GOOGLE_EMAIL=your@email.com GOOGLE_PASSWORD=yourpassword DOWNLOAD_AS=pdf npx tsx examples/slide-download-test.ts
2585
+
2586
+ # Or set environment variables separately
2587
+ export GOOGLE_EMAIL=your@email.com
2588
+ export GOOGLE_PASSWORD=yourpassword
2589
+ export DOWNLOAD_AS=pdf
2590
+ npx tsx examples/slide-download-test.ts
2591
+ ```
2592
+
2593
+ **SDK Method Parameters:**
2594
+ - `slideId` (string, required): The slide artifact ID
2595
+ - `outputPath` (string, required): Directory path to save the downloaded slides
2596
+ - `notebookId` (string, required): The notebook ID containing the slides
2597
+ - `downloadAs` (string, optional): Download format - `'pdf'` (default) or `'png'`
2598
+
2599
+ **Returns:** `{ filePath: string, data: Artifact }` - File path and artifact data
2600
+
2601
+ **Description:**
2602
+ Downloads a slide deck artifact as PDF (default) or PNG files. Uses Playwright for authentication and handles the download automatically. PDF format saves all slides in a single file, while PNG format saves each slide as a separate image file.
2603
+
2604
+ **Format Options:**
2605
+
2606
+ **PDF (default):**
2607
+ - Single PDF file containing all slides
2608
+ - Filename: `<artifact-title>.pdf`
2609
+ - Saved directly in the output directory
2610
+
2611
+ **PNG:**
2612
+ - Individual PNG files for each slide
2613
+ - Saved in a subfolder named after the artifact: `<artifact-title>/`
2614
+ - Filenames: `slide_1.png`, `slide_2.png`, etc.
2615
+
2616
+ **Important Notes:**
2617
+ - **Use `get()` to get slide URLs**: `get()` returns slide image URLs in `slideUrls` array, not downloaded files
2618
+ - **Use `download()` to download**: `download()` method downloads the slides to disk
2619
+ - Slides must be in `READY` state before downloading (check with `get()` first)
2620
+ - Requires cookies to be configured in the RPC client
2621
+ - Uses Playwright headless browser for authenticated download
2622
+ - PDF generation uses `pdf-lib` if available, falls back to PNG if not installed
2623
+ - PNG files are always saved individually in a subfolder
2624
+
2625
+ **Usage:**
2626
+ ```typescript
2627
+ // Get slide URLs (get() returns URLs only)
2628
+ const slides = await sdk.artifacts.get('slide-id', 'notebook-id')
2629
+ console.log(`Slide URLs: ${slides.slideUrls?.length || 0} slides`)
2630
+ slides.slideUrls?.forEach((url, i) => {
2631
+ console.log(`Slide ${i + 1}: ${url}`)
2632
+ })
2633
+
2634
+ // Download as PDF (default) - use download() method
2635
+ const result = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id')
2636
+ console.log(`PDF saved to: ${result.filePath}`)
2637
+
2638
+ // Download as PNG files - use download() method
2639
+ const resultPng = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id', {
2640
+ downloadAs: 'png'
2641
+ })
2642
+ console.log(`PNG files saved to: ${resultPng.filePath}`)
2643
+ ```
2644
+
2645
+ **Example Workflow:**
2646
+ ```typescript
2647
+ // 1. Check slide status and get URLs
2648
+ const slides = await sdk.artifacts.get('slide-id', 'notebook-id')
2649
+ console.log(`Slide URLs: ${slides.slideUrls?.length || 0} slides`)
2650
+ if (slides.state === ArtifactState.READY) {
2651
+ // 2. Download as PDF (default)
2652
+ const downloaded = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id')
2653
+ console.log(`Downloaded PDF: ${downloaded.filePath}`)
2654
+
2655
+ // Or download as PNG files
2656
+ const pngSlides = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id', {
2657
+ downloadAs: 'png'
2658
+ })
2659
+ console.log(`Downloaded PNGs: ${pngSlides.filePath}`)
2660
+ }
2661
+ ```
2662
+
2663
+ ---
2664
+
2665
+ ### Rename Artifact
2666
+
2667
+ **Method:** `sdk.artifacts.rename(artifactId, newTitle)`
2668
+
2669
+ **Example:** [artifact-rename.ts](examples/artifact-rename.ts)
2670
+
2671
+ **Parameters:**
2672
+ - `artifactId: string` - The artifact ID (required)
2673
+ - `newTitle: string` - New title (required)
2674
+
2675
+ **Returns:** `Promise<Artifact>`
2676
+
2677
+ **Description:**
2678
+ Renames an artifact. Updates only the title field. Works for all artifact types.
2679
+
2680
+ **Return Fields:**
2681
+ Same as `get()` - returns updated artifact with new title
2682
+
2683
+ <details>
2684
+ <summary><strong>Notes</strong></summary>
2685
+
2686
+ - Only updates the title - other fields remain unchanged
2687
+ - Works for all artifact types (quiz, flashcards, report, mind map, infographic, slide deck, audio, video)
2688
+ - Returns full artifact object after update
2689
+
2690
+ </details>
2691
+
2692
+ **Usage:**
2693
+ ```typescript
2694
+ // Rename any artifact
2695
+ const updated = await sdk.artifacts.rename('artifact-id', 'My Updated Quiz')
2696
+ console.log(`New title: ${updated.title}`)
2697
+
2698
+ // Rename audio artifact (use audioId from create() or list())
2699
+ const audio = await sdk.artifacts.audio.create('notebook-id')
2700
+ const renamed = await sdk.artifacts.rename(audio.audioId, 'My Audio Overview')
2701
+ ```
2702
+
2703
+ ---
2704
+
2705
+ ### Delete Artifact
2706
+
2707
+ **Method:** `sdk.artifacts.delete(artifactId, notebookId?)`
2708
+
2709
+ **Example:** [artifact-delete.ts](examples/artifact-delete.ts)
2710
+
2711
+ **Parameters:**
2712
+ - `artifactId: string` - The artifact ID from `create()` or `list()` (required)
2713
+ - `notebookId?: string` - Optional notebook ID (helpful if `get()` fails for audio/video)
2714
+
2715
+ **Returns:** `Promise<void>`
2716
+
2717
+ **Description:**
2718
+ Permanently deletes an artifact. Works for all artifact types. This action cannot be undone. Automatically detects artifact type and uses the correct RPC method.
2719
+
2720
+ <details>
2721
+ <summary><strong>Notes</strong></summary>
2722
+
2723
+ - Deletion is permanent and cannot be undone
2724
+ - Works for all artifact types (quiz, flashcards, report, mind map, infographic, slide deck, audio, video)
2725
+ - Automatically detects artifact type by calling `get()` first
2726
+ - Audio and video artifacts use V5N4be RPC with `[[2], artifactId]` structure
2727
+ - Other artifacts use WxBZtb RPC with `[artifactId]` structure
2728
+ - If `get()` fails, tries both methods (V5N4be first, then standard delete)
2729
+ - Audio and video artifacts have their own artifactId (not the notebook ID)
2730
+
2731
+ </details>
2732
+
2733
+ **Usage:**
2734
+ ```typescript
2735
+ // Delete any artifact (recommended - automatically detects type)
2736
+ await sdk.artifacts.delete('artifact-id')
2737
+
2738
+ // Delete with notebook ID (helpful if get() fails)
2739
+ await sdk.artifacts.delete('artifact-id', 'notebook-id')
2740
+
2741
+ // Note: Audio and video artifacts have their own artifactId from create() or list()
2742
+ const audio = await sdk.artifacts.audio.create('notebook-id')
2743
+ await sdk.artifacts.delete(audio.audioId) // Use audioId, not notebookId
2744
+ ```
2745
+
2746
+ ---
2747
+
2748
+ ### Share Artifact
2749
+
2750
+ **Method:** `sdk.artifacts.share(notebookId, options)`
2751
+
2752
+ **Example:** [artifact-share.ts](examples/artifact-share.ts)
2753
+
2754
+ **Parameters:**
2755
+ - `notebookId: string` - The notebook ID (required, artifacts are shared at notebook level)
2756
+ - `options: ShareArtifactOptions`
2757
+ - `users?: Array<{email: string, role: 2|3|4}>` - Users to share with (optional)
2758
+ - `notify?: boolean` - Notify users (default: true, only used when users are provided)
2759
+ - `accessType?: 1|2` - Access type: 1=anyone with link, 2=restricted (optional, default: 2)
2760
+
2761
+ **Returns:** `Promise<ShareArtifactResult>`
2762
+
2763
+ **Description:**
2764
+ Shares an artifact (or the notebook containing the artifact) with specific users or makes it publicly accessible via a shareable link. Artifacts are shared at the notebook level, so sharing an artifact shares the entire notebook.
2765
+
2766
+ **User Roles:**
2767
+
2768
+ | Role | Value | Description |
2769
+ |------|-------|-------------|
2770
+ | Editor | `2` | Can edit notebook content |
2771
+ | Viewer | `3` | Can view notebook only |
2772
+ | Remove | `4` | Remove user from shared list |
2773
+
2774
+ **Access Types:**
2775
+
2776
+ | Access Type | Value | Description |
2777
+ |-------------|-------|-------------|
2778
+ | Anyone with link | `1` | Public access via share link |
2779
+ | Restricted | `2` | Only specified users can access |
2780
+
2781
+ **Return Fields:**
2782
+ - `shareUrl: string` - Share URL (always present)
2783
+ - `success: boolean` - Whether the share operation succeeded
2784
+ - `notebookId: string` - The notebook ID that was shared
2785
+ - `accessType: 1|2` - Access type
2786
+ - `isShared: boolean` - Whether the notebook is shared
2787
+ - `users?: Array<{email: string, role: 2|3}>` - Users with access (if users were shared)
2788
+
2789
+ <details>
2790
+ <summary><strong>Validation</strong></summary>
2791
+
2792
+ - Email addresses are validated using regex before sharing
2793
+ - Throws `APIError` if any email is invalid
2794
+ - Must provide either `users` array or `accessType=1` (anyone with link)
2795
+ - Supports multiple users in a single call
2796
+
2797
+ </details>
2798
+
2799
+ <details>
2800
+ <summary><strong>Notes</strong></summary>
2801
+
2802
+ - Artifacts are shared at the notebook level - sharing an artifact shares the entire notebook
2803
+ - `notify` is only used when `users` are provided
2804
+ - Default: `true` (users are notified when permissions change)
2805
+ - Set to `false` to share silently
2806
+ - `shareUrl` is always returned (constructed from notebook ID if not explicitly shared)
2807
+
2808
+ </details>
2809
+
2810
+ **Usage:**
2811
+ ```typescript
2812
+ // Share with users (restricted access, notify enabled by default)
2813
+ const result = await sdk.artifacts.share('notebook-id', {
2814
+ users: [
2815
+ { email: 'user1@example.com', role: 2 }, // editor
2816
+ { email: 'user2@example.com', role: 3 }, // viewer
2817
+ ],
2818
+ notify: true,
2819
+ accessType: 2, // restricted
2820
+ })
2821
+
2822
+ // Share with users (silent, no notification)
2823
+ const result = await sdk.artifacts.share('notebook-id', {
2824
+ users: [
2825
+ { email: 'user@example.com', role: 2 },
2826
+ ],
2827
+ notify: false,
2828
+ accessType: 2,
2829
+ })
2830
+
2831
+ // Enable link sharing (anyone with link)
2832
+ const result = await sdk.artifacts.share('notebook-id', {
2833
+ accessType: 1, // anyone with link
2834
+ })
2835
+ console.log(`Share URL: ${result.shareUrl}`)
2836
+
2837
+ // Remove user (role: 4)
2838
+ const result = await sdk.artifacts.share('notebook-id', {
2839
+ users: [
2840
+ { email: 'user@example.com', role: 4 }, // remove
2841
+ ],
2842
+ accessType: 2,
2843
+ })
2844
+ ```
2845
+
2846
+ ## Generation & Chat
2847
+
2848
+ Examples: [chat-basic.ts](examples/chat-basic.ts) | [chat-conversation.ts](examples/chat-conversation.ts) | [generation-set-chat-config.ts](examples/generation-set-chat-config.ts)
2849
+
2850
+ **Key Features:**
2851
+ - ✅ **Streaming & Non-streaming modes** - Choose real-time streaming (`chatStream()`) or complete responses (`chat()`)
2852
+ - ✅ **Source selection** - Chat with all sources or specific ones (interactive or programmatic)
2853
+ - ✅ **Citation extraction** - Automatic citation tracking from responses
2854
+ - ✅ **Conversation management** - Track conversations with IDs and history
2855
+ - ✅ **Type-safe configuration** - Full TypeScript support with `ChatConfig` interface
2856
+ - ✅ **Improved parser** - Based on Python SDK implementation for better reliability
2857
+
2858
+ **Choosing Between `chat()` and `chatStream()`:**
2859
+ - **Use `chat()`** when you want the complete response at once (simpler, blocking)
2860
+ - Returns complete response text after all chunks are received
2861
+ - Best for scripts, automation, or when you need the full response before processing
2862
+ - Use the `--no-stream` flag in the example script
2863
+ - **Use `chatStream()`** when you want real-time updates (better UX, progressive display)
2864
+ - Yields chunks as they arrive for real-time display
2865
+ - Automatically handles thinking content buffering and revision detection
2866
+ - Only displays the final response (no thinking steps or revision markers)
2867
+ - Best for interactive applications or when you want immediate feedback
2868
+ - Both methods support the same options (source selection, conversation history, etc.)
2869
+ - Both methods extract citations and track conversation metadata
2870
+
2871
+ ---
2872
+
2873
+ ### Chat (Non-Streaming)
2874
+
2875
+ **Method:** `sdk.generation.chat(notebookId, prompt, options?)`
2876
+
2877
+ **Examples:**
2878
+ - [chat-basic.ts](examples/chat-basic.ts) - Basic chat with all sources
2879
+ - [chat-conversation.ts](examples/chat-conversation.ts) - Chat with conversation history
2880
+
2881
+ **Note:** The SDK now uses an improved parser based on the Python SDK implementation, providing better error handling, citation extraction, and streaming support. The chat request format has been restructured to match the official API format for better compatibility.
2882
+
2883
+ **Parameters:**
2884
+ - `notebookId: string` - The notebook ID (required)
2885
+ - `prompt: string` - Chat message/prompt (required)
2886
+ - `options?: object` - Optional chat options:
2887
+ - `sourceIds?: string[]` - Specific source IDs to query (uses all sources if omitted)
2888
+ - `conversationHistory?: Array<{ message: string; role: 'user' | 'assistant' }>` - Conversation history for follow-up messages
2889
+ - `conversationId?: string` - Conversation ID for continuing a conversation (auto-generated if not provided)
2890
+
2891
+ **Returns:** `Promise<ChatResponseData>` - Complete AI response with metadata
2892
+
2893
+ **Type Import:**
2894
+ ```typescript
2895
+ import type { ChatResponseData } from 'notebooklm-kit';
2896
+ ```
2897
+
2898
+ **ChatResponseData Interface:**
2899
+ ```typescript
2900
+ interface ChatResponseData {
2901
+ text: string; // Complete response text (thinking headers removed)
2902
+ rawData?: any; // Raw response data from API
2903
+ chunks?: StreamChunk[]; // All chunks received during streaming
2904
+ conversationId?: string; // Conversation ID for continuing the conversation
2905
+ citations: number[]; // Citation numbers extracted from response
2906
+ }
2907
+ ```
2908
+
2909
+ **Description:**
2910
+ Chat with your notebook content using AI. Returns the complete response after all chunks are received. This is the non-streaming mode - use `chatStream()` for real-time streaming responses.
2911
+
2912
+ **Response Format:**
2913
+ - `text`: The complete response text with thinking headers automatically removed
2914
+ - `rawData`: Raw response structure from the API (for advanced use cases)
2915
+ - `chunks`: Array of all stream chunks received (if you need to inspect individual chunks)
2916
+ - `conversationId`: ID for continuing the conversation
2917
+ - `citations`: Array of citation numbers found in the response (e.g., `[1, 2, 3]`)
2918
+
2919
+ **Features:**
2920
+ - ✅ Automatic source detection (uses all sources if none specified)
2921
+ - ✅ Source selection support (filter to specific sources)
2922
+ - ✅ Conversation history tracking
2923
+ - ✅ Citation extraction
2924
+ - ✅ Conversation ID management
2925
+ - ✅ Type-safe options
2926
+
2927
+ <details>
2928
+ <summary><strong>Notes</strong></summary>
2929
+
2930
+ - **Response format**: Returns `ChatResponseData` object with `text`, `citations`, `conversationId`, etc.
2931
+ - **Text extraction**: The `text` field contains the complete response with thinking headers automatically removed
2932
+ - **Citation extraction**: Citations are automatically extracted and available in the `citations` array
2933
+ - **Conversation tracking**: Conversation ID is auto-generated if not provided and returned in response
2934
+ - **Source selection**: If `sourceIds` is provided, only those sources are used for context
2935
+ - **Auto source detection**: If `sourceIds` is omitted, all sources in the notebook are automatically fetched and used
2936
+ - **Conversation history**: Use `conversationHistory` for follow-up messages to maintain context
2937
+ - **Quota management**: Quota is checked before chat (if quota manager is enabled)
2938
+ - **Usage tracking**: Usage is recorded after successful chat
2939
+ - **Response aggregation**: Response is aggregated from all streaming chunks and returned as complete text
2940
+ - **For streaming**: Use `chatStream()` for real-time streaming responses
2941
+
2942
+ </details>
2943
+
2944
+ **Usage:**
2945
+ ```typescript
2946
+ // Chat with all sources (non-streaming)
2947
+ const response = await sdk.generation.chat(
2948
+ 'notebook-id',
2949
+ 'What are the main findings from the research?'
2950
+ )
2951
+ console.log(response.text) // Complete response text
2952
+ console.log(`Citations: [${response.citations.join(', ')}]`)
2953
+ console.log(`Conversation ID: ${response.conversationId}`)
2954
+
2955
+ // Chat with specific sources
2956
+ const response = await sdk.generation.chat(
2957
+ 'notebook-id',
2958
+ 'Summarize the methodology section',
2959
+ { sourceIds: ['source-id-1', 'source-id-2'] }
2960
+ )
2961
+ console.log(response.text)
2962
+
2963
+ // Follow-up message with conversation history
2964
+ const response1 = await sdk.generation.chat('notebook-id', 'What is machine learning?')
2965
+ const response2 = await sdk.generation.chat('notebook-id', 'Tell me more', {
2966
+ conversationId: response1.conversationId,
2967
+ conversationHistory: [
2968
+ { message: 'What is machine learning?', role: 'user' },
2969
+ { message: response1.text, role: 'assistant' }
2970
+ ]
2971
+ })
2972
+ console.log(response2.text)
2973
+ ```
2974
+
2975
+ ---
2976
+
2977
+ ### Chat Stream (Streaming)
2978
+
2979
+ **Method:** `sdk.generation.chatStream(notebookId, prompt, options?)`
2980
+
2981
+ **Examples:**
2982
+ - [chat-basic.ts](examples/chat-basic.ts) - Streaming chat with all sources
2983
+ - [chat-conversation.ts](examples/chat-conversation.ts) - Streaming multi-turn conversations
2984
+
2985
+ **Parameters:**
2986
+ - `notebookId: string` - The notebook ID (required)
2987
+ - `prompt: string` - Chat message/prompt (required)
2988
+ - `options?: object` - Optional chat options:
2989
+ - `sourceIds?: string[]` - Specific source IDs to query (uses all sources if omitted)
2990
+ - `conversationHistory?: Array<{ message: string; role: 'user' | 'assistant' }>` - Conversation history for follow-up messages
2991
+ - `conversationId?: string` - Conversation ID for continuing a conversation (auto-generated if not provided)
2992
+ - `onChunk?: (chunk: StreamChunk) => void` - Callback function called for each chunk
2993
+ - `showThinking?: boolean` - Whether to include thinking process in output (default: false)
2994
+
2995
+ **Returns:** `AsyncGenerator<StreamChunk, void, unknown>` - Async generator yielding stream chunks
2996
+
2997
+ **Type Import:**
2998
+ ```typescript
2999
+ import type { StreamChunk } from 'notebooklm-kit';
3000
+ ```
3001
+
3002
+ **Description:**
3003
+ Stream chat responses in real-time. Returns an async generator that yields chunks as they arrive from the API. Each chunk contains the **full accumulated text** up to that point (snapshot-based, not delta-based), allowing you to display responses as they're generated.
3004
+
3005
+ **Key Behaviors:**
3006
+ - **Snapshot-based streaming**: Each `chunk.text` contains the complete response accumulated so far, not just the new portion
3007
+ - **Thinking content buffering**: Thinking content (marked with `**Header**`) is automatically buffered and only the final response is displayed
3008
+ - **Revision detection**: If the AI revises its response mid-stream, the revision is automatically handled and only the final version is shown
3009
+ - **No revision markers**: The streaming client automatically filters out thinking steps and revision markers for a clean output
3010
+
3011
+ **StreamChunk Interface:**
3012
+ ```typescript
3013
+ interface StreamChunk {
3014
+ chunkNumber: number; // Chunk number (1-based, increments with each chunk)
3015
+ byteCount: number; // Byte count for this chunk
3016
+ text: string; // FULL accumulated text from start to this point (snapshot-based)
3017
+ thinking: string[]; // Thinking headers extracted from text (e.g., ["Analyzing sources", "Formulating response"])
3018
+ response: string; // Response text with thinking headers removed
3019
+ metadata?: [string, string, number]; // [conversationId, messageId, timestamp]
3020
+ messageIds?: [string, string]; // Message IDs: [conversationId, messageId]
3021
+ timestamp?: number; // Timestamp from metadata
3022
+ citations?: number[]; // Citation numbers extracted from text (e.g., [1, 2, 3])
3023
+ rawData?: any; // Raw parsed data from API
3024
+ isError?: boolean; // Is this an error chunk?
3025
+ errorCode?: number; // Error code if isError is true
3026
+ isThinking?: boolean; // Does this chunk contain thinking content?
3027
+ isResponse?: boolean; // Does this chunk contain response content?
3028
+ formatting?: any; // Formatting information
3029
+ }
3030
+ ```
3031
+
3032
+ **Important Notes:**
3033
+ - `chunk.text` contains the **complete accumulated response** (not incremental)
3034
+ - To display incrementally, compare `chunk.text.length` with previous chunk length
3035
+ - Thinking content is automatically filtered - you'll only see the final response
3036
+ - Citations are extracted from the text using pattern matching `[1]`, `[2]`, etc.
3037
+ - Conversation ID is available in `chunk.metadata[0]` or `chunk.messageIds[0]`
3038
+
3039
+ **Features:**
3040
+ - ✅ Real-time streaming responses
3041
+ - ✅ Citation extraction from each chunk
3042
+ - ✅ Conversation metadata tracking
3043
+ - ✅ Thinking/response separation
3044
+ - ✅ Error detection and handling
3045
+ - ✅ Progress callbacks via `onChunk`
3046
+
3047
+ <details>
3048
+ <summary><strong>Notes</strong></summary>
3049
+
3050
+ - **Snapshot-based streaming**: Each `chunk.text` contains the complete accumulated response from the start, not just the new portion
3051
+ - **Incremental display**: To display incrementally, compare `chunk.text.length` with previous chunk length and extract the new portion
3052
+ - **Thinking content handling**: Thinking content (marked with `**Header**`) is automatically buffered and filtered - only the final response is displayed
3053
+ - **Revision detection**: If the AI revises its response mid-stream, the revision is automatically detected and only the final version is shown
3054
+ - **No revision markers**: The client automatically handles revisions without showing "Response revised by AI" markers
3055
+ - **Citation extraction**: Citations are automatically extracted from text using pattern matching `[1]`, `[2]`, etc.
3056
+ - **Conversation tracking**: Conversation ID and message IDs are available in `chunk.metadata` or `chunk.messageIds`
3057
+ - **Quota management**: Quota is checked before streaming starts (if quota manager is enabled)
3058
+ - **Usage tracking**: Usage is recorded after streaming completes
3059
+ - **Callback support**: Use `onChunk` callback for real-time processing of each chunk
3060
+ - **Error handling**: Error chunks are detected via `chunk.isError` and `chunk.errorCode`
3061
+
3062
+ </details>
3063
+
3064
+ **Usage:**
3065
+
3066
+ **Basic Streaming (Snapshot-based):**
3067
+ ```typescript
3068
+ // Since chunk.text contains the FULL accumulated response, display incrementally
3069
+ let lastDisplayedLength = 0;
3070
+
3071
+ for await (const chunk of sdk.generation.chatStream('notebook-id', 'What is this about?')) {
3072
+ // chunk.text contains complete response so far - extract only new portion
3073
+ if (chunk.text.length > lastDisplayedLength) {
3074
+ const newText = chunk.text.substring(lastDisplayedLength);
3075
+ process.stdout.write(newText);
3076
+ lastDisplayedLength = chunk.text.length;
3077
+ }
3078
+ }
3079
+ ```
3080
+
3081
+ **Simple Streaming (Using response field):**
3082
+ ```typescript
3083
+ // Use chunk.response which has thinking headers already removed
3084
+ let lastResponseLength = 0;
3085
+
3086
+ for await (const chunk of sdk.generation.chatStream('notebook-id', 'Explain this')) {
3087
+ if (chunk.response && chunk.response.length > lastResponseLength) {
3088
+ const newText = chunk.response.substring(lastResponseLength);
3089
+ process.stdout.write(newText);
3090
+ lastResponseLength = chunk.response.length;
3091
+ }
3092
+ }
3093
+ ```
3094
+
3095
+ **Streaming with Callback:**
3096
+ ```typescript
3097
+ for await (const chunk of sdk.generation.chatStream('notebook-id', 'Explain this', {
3098
+ onChunk: (chunk) => {
3099
+ console.log(`Chunk ${chunk.chunkNumber}: ${chunk.byteCount} bytes`);
3100
+ if (chunk.citations && chunk.citations.length > 0) {
3101
+ console.log(`Citations: ${chunk.citations.join(', ')}`);
3102
+ }
3103
+ }
3104
+ })) {
3105
+ // Display incrementally
3106
+ if (chunk.text.length > lastDisplayedLength) {
3107
+ const newText = chunk.text.substring(lastDisplayedLength);
3108
+ process.stdout.write(newText);
3109
+ lastDisplayedLength = chunk.text.length;
3110
+ }
3111
+ }
3112
+ ```
3113
+
3114
+ **Streaming with Specific Sources:**
3115
+ ```typescript
3116
+ let lastDisplayedLength = 0;
3117
+
3118
+ for await (const chunk of sdk.generation.chatStream(
3119
+ 'notebook-id',
3120
+ 'Compare these sources',
3121
+ { sourceIds: ['source-id-1', 'source-id-2'] }
3122
+ )) {
3123
+ if (chunk.text.length > lastDisplayedLength) {
3124
+ const newText = chunk.text.substring(lastDisplayedLength);
3125
+ process.stdout.write(newText);
3126
+ lastDisplayedLength = chunk.text.length;
3127
+ }
3128
+ }
3129
+ ```
3130
+
3131
+ **Collect Citations and Metadata:**
3132
+ ```typescript
3133
+ const citations = new Set<number>();
3134
+ let conversationId: string | undefined;
3135
+ let messageIds: [string, string] | undefined;
3136
+ let lastDisplayedLength = 0;
3137
+
3138
+ for await (const chunk of sdk.generation.chatStream('notebook-id', 'What are the key findings?')) {
3139
+ // Track conversation ID and message IDs
3140
+ if (chunk.metadata) {
3141
+ conversationId = chunk.metadata[0];
3142
+ messageIds = chunk.metadata.slice(0, 2) as [string, string];
3143
+ }
3144
+
3145
+ // Collect citations
3146
+ if (chunk.citations) {
3147
+ chunk.citations.forEach(citation => citations.add(citation));
3148
+ }
3149
+
3150
+ // Display response incrementally
3151
+ if (chunk.text.length > lastDisplayedLength) {
3152
+ const newText = chunk.text.substring(lastDisplayedLength);
3153
+ process.stdout.write(newText);
3154
+ lastDisplayedLength = chunk.text.length;
3155
+ }
3156
+ }
3157
+
3158
+ console.log(`\nConversation ID: ${conversationId}`);
3159
+ console.log(`Message IDs: ${messageIds?.join(', ')}`);
3160
+ console.log(`Citations: [${Array.from(citations).sort((a, b) => a - b).join(', ')}]`);
3161
+ ```
3162
+
3163
+ **Example Output Format:**
3164
+ ```
3165
+ The provided sources primarily discuss the field of Artificial Intelligence (AI)
3166
+ and the transformative research paper "Attention Is All You Need" [1, 2].
3167
+
3168
+ The transformer architecture introduced in 2017 revolutionized AI by enabling
3169
+ parallel processing and becoming the foundation for modern large language models [3, 4].
3170
+ ```
3171
+
3172
+ **Note:** The streaming client automatically:
3173
+ - Buffers thinking content (won't display it)
3174
+ - Detects and handles revisions (only shows final response)
3175
+ - Removes thinking headers from output
3176
+ - Extracts citations from text
3177
+ - Tracks conversation metadata
3178
+
3179
+ ---
3180
+
3181
+ ### Set Chat Configuration
3182
+
3183
+ **Method:** `sdk.generation.setChatConfig(notebookId, config)`
3184
+
3185
+ **Example:** [generation-set-chat-config.ts](examples/generation-set-chat-config.ts)
3186
+
3187
+ **Parameters:**
3188
+ - `notebookId: string` - The notebook ID (required)
3189
+ - `config: ChatConfig` - Chat configuration object (type-safe):
3190
+ - `type: 'default' | 'custom' | 'learning-guide'` - Configuration type (required)
3191
+ - `customText?: string` - Custom prompt text (required if type is 'custom')
3192
+ - `responseLength: 'default' | 'shorter' | 'longer'` - Response length (required)
3193
+
3194
+ **Returns:** `Promise<any>` - Configuration result
3195
+
3196
+ **Type Import:**
3197
+ ```typescript
3198
+ import type { ChatConfig } from 'notebooklm-kit';
3199
+ ```
3200
+
3201
+ **Description:**
3202
+ Configure chat behavior before sending messages. Set the chat mode (default, custom prompt, or learning guide) and response length. This configuration affects all subsequent chat messages until changed. This is optional - you can use chat without setting configuration.
3203
+
3204
+ **Configuration Types:**
3205
+ - **`default`**: Standard conversational responses - balanced and informative
3206
+ - **`custom`**: Responses following a custom instruction/persona (requires `customText`)
3207
+ - **`learning-guide`**: Educational responses optimized for learning and understanding
3208
+
3209
+ **Response Lengths:**
3210
+ - **`default`**: Standard length responses - balanced detail
3211
+ - **`shorter`**: Concise, brief responses - quick summaries
3212
+ - **`longer`**: Detailed, comprehensive responses - in-depth explanations
3213
+
3214
+ **Usage:**
3215
+ ```typescript
3216
+ // Set default configuration
3217
+ await sdk.generation.setChatConfig('notebook-id', {
3218
+ type: 'default',
3219
+ responseLength: 'default'
3220
+ })
3221
+
3222
+ // Set custom configuration with custom prompt
3223
+ await sdk.generation.setChatConfig('notebook-id', {
3224
+ type: 'custom',
3225
+ customText: 'respond as a PhD student explaining complex concepts simply',
3226
+ responseLength: 'longer'
3227
+ })
3228
+
3229
+ // Set learning guide configuration
3230
+ await sdk.generation.setChatConfig('notebook-id', {
3231
+ type: 'learning-guide',
3232
+ responseLength: 'shorter'
3233
+ })
3234
+
3235
+ // Example: Configure for academic writing style
3236
+ await sdk.generation.setChatConfig('notebook-id', {
3237
+ type: 'custom',
3238
+ customText: 'respond in an academic writing style with citations',
3239
+ responseLength: 'longer'
3240
+ })
3241
+ ```
3242
+
3243
+ **Note:** Configuration persists for the notebook until changed. You can update it anytime by calling `setChatConfig()` again with new values.
3244
+
3245
+ ---
3246
+
3247
+ ---
3248
+ - ⚠️ This action is permanent and cannot be undone
3249
+ - Each conversation has a unique ID that persists across sessions
3250
+ - Use conversation IDs to manage multiple parallel conversations
3251
+ - Deleting a conversation removes all message history for that conversation
3252
+
3253
+ ---
3254
+
3255
+ ## Notes
3256
+
3257
+ Examples: [note-list.ts](examples/note-list.ts) | [note-create.ts](examples/note-create.ts) | [note-update.ts](examples/note-update.ts) | [note-delete.ts](examples/note-delete.ts)
3258
+
3259
+ ### List Notes
3260
+
3261
+ **Method:** `sdk.notes.list(notebookId)`
3262
+
3263
+ **Example:** [note-list.ts](examples/note-list.ts)
3264
+
3265
+ **Parameters:**
3266
+ - `notebookId: string` - The notebook ID (required)
3267
+
3268
+ **Returns:** `Promise<Note[]>`
3269
+
3270
+ **Description:**
3271
+ Lists all notes in a notebook. Returns an array of notes with their titles, content, and metadata.
3272
+
3273
+ **Return Fields:**
3274
+ - `noteId: string` - Unique note ID (required for update/delete operations)
3275
+ - `title: string` - Note title
3276
+ - `content: string` - Note content
3277
+ - `tags?: string[]` - Note tags (if any)
3278
+ - `createdAt?: string` - Creation timestamp (if available)
3279
+ - `updatedAt?: string` - Last modified timestamp (if available)
3280
+
3281
+ <details>
3282
+ <summary><strong>Notes</strong></summary>
3283
+
3284
+ - Returns empty array if notebook has no notes
3285
+ - Notes are returned in the order they appear in the notebook
3286
+ - Content may be truncated in list view (use individual note operations for full content)
3287
+ - Tags are optional and may be empty
3288
+
3289
+ </details>
3290
+
3291
+ **Usage:**
3292
+ ```typescript
3293
+ const notes = await sdk.notes.list('notebook-id')
3294
+ console.log(`Found ${notes.length} notes`)
3295
+
3296
+ notes.forEach((note, index) => {
3297
+ console.log(`${index + 1}. ${note.title}`)
3298
+ console.log(` ID: ${note.noteId}`)
3299
+ if (note.tags && note.tags.length > 0) {
3300
+ console.log(` Tags: ${note.tags.join(', ')}`)
3301
+ }
3302
+ })
3303
+ ```
3304
+
3305
+ ---
3306
+
3307
+ ### Create Note
3308
+
3309
+ **Method:** `sdk.notes.create(notebookId, options)`
3310
+
3311
+ **Example:** [note-create.ts](examples/note-create.ts)
3312
+
3313
+ **Parameters:**
3314
+ - `notebookId: string` - The notebook ID (required)
3315
+ - `options: CreateNoteOptions`
3316
+ - `title: string` - Note title (required)
3317
+ - `content?: string` - Note content (optional, defaults to empty string)
3318
+ - `tags?: string[]` - Note tags (optional)
3319
+ - `noteType?: NoteType[]` - Note type (optional, defaults to `[NoteType.REGULAR]`)
3320
+
3321
+ **Returns:** `Promise<Note>`
3322
+
3323
+ **Description:**
3324
+ Creates a new note in the notebook. Notes are useful for adding your own annotations, reminders, or summaries alongside the notebook content.
3325
+
3326
+ **Return Fields:**
3327
+ - `noteId: string` - Unique note ID (use this for update/delete operations)
3328
+ - `title: string` - Note title (as provided)
3329
+ - `content: string` - Note content (may be empty initially)
3330
+
3331
+ <details>
3332
+ <summary><strong>Notes</strong></summary>
3333
+
3334
+ - Title is required - cannot create a note without a title
3335
+ - Content is optional and can be added later via `update()`
3336
+ - Tags are optional and can be added during creation or later
3337
+ - Note type defaults to `REGULAR` (1) - use `GENERATED` (2) for AI-generated notes
3338
+ - Returns immediately with note ID - no waiting required
3339
+
3340
+ </details>
3341
+
3342
+ **Usage:**
3343
+ ```typescript
3344
+ // Create a simple note
3345
+ const note = await sdk.notes.create('notebook-id', {
3346
+ title: 'Meeting Notes',
3347
+ content: 'Key points from today\'s meeting...',
3348
+ })
3349
+ console.log(`Created note: ${note.noteId}`)
3350
+
3351
+ // Create a note with tags
3352
+ const note = await sdk.notes.create('notebook-id', {
3353
+ title: 'Research Findings',
3354
+ content: 'Important findings...',
3355
+ tags: ['research', 'findings'],
3356
+ })
3357
+
3358
+ // Create a note with just a title (add content later)
3359
+ const note = await sdk.notes.create('notebook-id', {
3360
+ title: 'Quick Reminder',
3361
+ })
3362
+ ```
3363
+
3364
+ ---
3365
+
3366
+ ### Update Note
3367
+
3368
+ **Method:** `sdk.notes.update(notebookId, noteId, options)`
3369
+
3370
+ **Example:** [note-update.ts](examples/note-update.ts)
3371
+
3372
+ **Parameters:**
3373
+ - `notebookId: string` - The notebook ID (required)
3374
+ - `noteId: string` - The note ID (required)
3375
+ - `options: UpdateNoteOptions`
3376
+ - `title?: string` - New title (optional, defaults to empty string)
3377
+ - `content?: string` - New content (optional, defaults to empty string)
3378
+ - `tags?: string[]` - New tags (optional, defaults to empty array)
3379
+
3380
+ **Returns:** `Promise<Note>`
3381
+
3382
+ **Description:**
3383
+ Updates a note's title, content, and tags. All fields can be updated together or individually. If a field is not provided, it defaults to an empty value.
3384
+
3385
+ <details>
3386
+ <summary><strong>Notes</strong></summary>
3387
+
3388
+ - Both `title` and `content` are always sent (defaults to empty string if not provided)
3389
+ - Tags default to empty array if not provided
3390
+ - All fields are updated together in a single operation
3391
+ - Returns updated note object with the provided title
3392
+
3393
+ </details>
3394
+
3395
+ **Usage:**
3396
+ ```typescript
3397
+ // Update title and content
3398
+ const updated = await sdk.notes.update('notebook-id', 'note-id', {
3399
+ title: 'Updated Meeting Notes',
3400
+ content: 'Updated content with new information...',
3401
+ })
3402
+
3403
+ // Update all fields including tags
3404
+ const updated = await sdk.notes.update('notebook-id', 'note-id', {
3405
+ title: 'Final Meeting Notes',
3406
+ content: 'Final content...',
3407
+ tags: ['meeting', 'final'],
3408
+ })
3409
+
3410
+ // Update both title and content
3411
+ const updated = await sdk.notes.update('notebook-id', 'note-id', {
3412
+ title: 'Final Meeting Notes',
3413
+ content: 'Final content...',
3414
+ tags: ['meeting', 'final'],
3415
+ })
3416
+ ```
3417
+
3418
+ ---
3419
+
3420
+ ### Delete Note
3421
+
3422
+ **Method:** `sdk.notes.delete(notebookId, noteIds)`
3423
+
3424
+ **Example:** [note-delete.ts](examples/note-delete.ts)
3425
+
3426
+ **Parameters:**
3427
+ - `notebookId: string` - The notebook ID (required)
3428
+ - `noteIds: string | string[]` - Single note ID or array of note IDs (required)
3429
+
3430
+ **Returns:** `Promise<void>`
3431
+
3432
+ **Description:**
3433
+ Deletes one or more notes from the notebook. This action cannot be undone.
3434
+
3435
+ <details>
3436
+ <summary><strong>Notes</strong></summary>
3437
+
3438
+ - Supports both single note ID and array of note IDs
3439
+ - Batch deletion is supported (pass array of IDs)
3440
+ - Deletion is permanent and cannot be undone
3441
+ - No confirmation required - deletion is immediate
3442
+
3443
+ </details>
3444
+
3445
+ **Usage:**
3446
+ ```typescript
3447
+ // Delete single note
3448
+ await sdk.notes.delete('notebook-id', 'note-id')
3449
+
3450
+ // Delete multiple notes
3451
+ await sdk.notes.delete('notebook-id', [
3452
+ 'note-id-1',
3453
+ 'note-id-2',
3454
+ 'note-id-3',
3455
+ ])
3456
+ ```
3457
+
3458
+ ## Language Support
3459
+
3460
+ NotebookLM supports **80+ languages** for artifacts, chat responses, and all notebook operations.
3461
+
3462
+ ### Notebook Default Language
3463
+
3464
+ Each notebook has a **default output language** that is used for:
3465
+ - Artifact creation (audio, video, report, infographics, slide decks)
3466
+ - Chat responses
3467
+ - All other notebook operations
3468
+
3469
+ **If you don't specify a language when creating an artifact, it will use the notebook's default language.**
3470
+
3471
+ #### Get Notebook Default Language
3472
+
3473
+ ```typescript
3474
+ // Get the current default language for a notebook
3475
+ const language = await sdk.notebookLanguage.get('notebook-id');
3476
+ console.log(`Default language: ${language}`); // 'en', 'de', 'ja', etc.
3477
+ ```
3478
+
3479
+ #### Set Notebook Default Language
3480
+
3481
+ ```typescript
3482
+ import { NotebookLMLanguage } from 'notebooklm-kit';
3483
+
3484
+ // Set the notebook's default language to German
3485
+ await sdk.notebookLanguage.set('notebook-id', NotebookLMLanguage.GERMAN);
3486
+
3487
+ // Set to Japanese
3488
+ await sdk.notebookLanguage.set('notebook-id', NotebookLMLanguage.JAPANESE);
3489
+
3490
+ // Set using language code directly
3491
+ await sdk.notebookLanguage.set('notebook-id', 'de');
3492
+ ```
3493
+
3494
+ #### Get Language Information
3495
+
3496
+ ```typescript
3497
+ // Get language info with metadata
3498
+ const info = await sdk.notebookLanguage.getInfo('notebook-id');
3499
+ console.log(`Language: ${info.language}`); // 'de'
3500
+ console.log(`Name: ${info.name}`); // 'German'
3501
+ console.log(`Native Name: ${info.nativeName}`); // 'Deutsch'
3502
+ ```
3503
+
3504
+ ### Supported Languages
3505
+
3506
+ Use the `NotebookLMLanguage` enum for type safety:
3507
+
3508
+ ```typescript
3509
+ import { NotebookLMLanguage } from 'notebooklm-kit'
3510
+
3511
+ NotebookLMLanguage.ENGLISH // 'en'
3512
+ NotebookLMLanguage.HINDI // 'hi'
3513
+ NotebookLMLanguage.SPANISH // 'es'
3514
+ NotebookLMLanguage.FRENCH // 'fr'
3515
+ NotebookLMLanguage.GERMAN // 'de'
3516
+ NotebookLMLanguage.JAPANESE // 'ja'
3517
+ NotebookLMLanguage.CHINESE_SIMPLIFIED // 'zh'
3518
+ NotebookLMLanguage.ARABIC // 'ar'
3519
+ NotebookLMLanguage.TURKISH // 'tr'
3520
+ // ... and 70+ more languages
3521
+ ```
3522
+
3523
+ ### Artifact Language Support
3524
+
3525
+ **Artifacts that support language customization:**
3526
+ - ✅ **Audio Overview** - `customization.language`
3527
+ - ✅ **Video Overview** - `customization.language`
3528
+ - ✅ **Report** - Uses notebook default language automatically
3529
+ - ✅ **Infographic** - `customization.language`
3530
+ - ✅ **Slide Deck** - `customization.language`
3531
+
3532
+ **Artifacts that don't support language customization:**
3533
+ - ❌ **Quiz** - Language is set via instructions, not customization
3534
+ - ❌ **Flashcards** - Language is set via instructions, not customization
3535
+ - ❌ **Mind Map** - No language customization available
3536
+
3537
+ ### Using Language in Artifacts
3538
+
3539
+ #### Option 1: Use Notebook Default (Recommended)
3540
+
3541
+ ```typescript
3542
+ // Set notebook default language once
3543
+ await sdk.notebookLanguage.set('notebook-id', NotebookLMLanguage.GERMAN);
3544
+
3545
+ // All artifacts will use German by default
3546
+ const audio = await sdk.artifacts.create('notebook-id', ArtifactType.AUDIO, {
3547
+ // No language specified - uses notebook default (German)
3548
+ });
3549
+
3550
+ const video = await sdk.artifacts.create('notebook-id', ArtifactType.VIDEO, {
3551
+ // No language specified - uses notebook default (German)
3552
+ });
3553
+ ```
3554
+
3555
+ #### Option 2: Override for Specific Artifacts
3556
+
3557
+ ```typescript
3558
+ // Set notebook default to German
3559
+ await sdk.notebookLanguage.set('notebook-id', NotebookLMLanguage.GERMAN);
3560
+
3561
+ // Most artifacts use German
3562
+ const audio = await sdk.artifacts.create('notebook-id', ArtifactType.AUDIO, {
3563
+ // Uses German (notebook default)
3564
+ });
3565
+
3566
+ // But this one uses Japanese
3567
+ const video = await sdk.artifacts.create('notebook-id', ArtifactType.VIDEO, {
3568
+ customization: {
3569
+ language: NotebookLMLanguage.JAPANESE, // Overrides notebook default
3570
+ },
3571
+ });
3572
+ ```
3573
+
3574
+ #### Option 3: Explicit Language for Each Artifact
3575
+
3576
+ ```typescript
3577
+ // Always specify language explicitly
3578
+ const audio = await sdk.artifacts.create('notebook-id', ArtifactType.AUDIO, {
3579
+ customization: {
3580
+ language: NotebookLMLanguage.SPANISH,
3581
+ },
3582
+ });
3583
+
3584
+ const video = await sdk.artifacts.create('notebook-id', ArtifactType.VIDEO, {
3585
+ customization: {
3586
+ language: NotebookLMLanguage.FRENCH,
3587
+ },
3588
+ });
3589
+ ```
3590
+
3591
+ ### Language Examples
3592
+
3593
+ ```typescript
3594
+ import { NotebookLMLanguage } from 'notebooklm-kit';
3595
+
3596
+ // Create artifacts in different languages
3597
+ const germanAudio = await sdk.artifacts.create('notebook-id', ArtifactType.AUDIO, {
3598
+ customization: {
3599
+ language: NotebookLMLanguage.GERMAN, // 'de'
3600
+ },
3601
+ });
3602
+
3603
+ const japaneseVideo = await sdk.artifacts.create('notebook-id', ArtifactType.VIDEO, {
3604
+ customization: {
3605
+ language: NotebookLMLanguage.JAPANESE, // 'ja'
3606
+ },
3607
+ });
3608
+
3609
+ const hindiSlides = await sdk.artifacts.create('notebook-id', ArtifactType.SLIDE_DECK, {
3610
+ customization: {
3611
+ language: NotebookLMLanguage.HINDI, // 'hi'
3612
+ },
3613
+ });
3614
+
3615
+ const spanishInfographic = await sdk.artifacts.create('notebook-id', ArtifactType.INFOGRAPHIC, {
3616
+ customization: {
3617
+ language: NotebookLMLanguage.SPANISH, // 'es'
3618
+ },
3619
+ });
3620
+ ```
3621
+
3622
+ ## Advanced Configuration
3623
+
3624
+ ```typescript
3625
+ const sdk = new NotebookLMClient({
3626
+ authToken: process.env.NOTEBOOKLM_AUTH_TOKEN!,
3627
+ cookies: process.env.NOTEBOOKLM_COOKIES!,
3628
+
3629
+ // Enable debug logging
3630
+ debug: true,
3631
+
3632
+ // Auto-refresh configuration
3633
+ autoRefresh: {
3634
+ enabled: true,
3635
+ interval: 5 * 60 * 1000, // 5 minutes
3636
+ },
3637
+
3638
+ // Retry configuration
3639
+ maxRetries: 3,
3640
+
3641
+ // Custom headers
3642
+ headers: {
3643
+ 'User-Agent': 'My Custom Agent',
3644
+ },
3645
+ })
3646
+
3647
+ // Manually refresh
3648
+ await sdk.refreshCredentials()
3649
+
3650
+ // Get RPC client
3651
+ const rpcClient = sdk.getRPCClient()
3652
+ ```
3653
+
3654
+ ## Error Handling
3655
+
3656
+ ```typescript
3657
+ import {
3658
+ NotebookLMError,
3659
+ NotebookLMAuthError,
3660
+ RateLimitError,
3661
+ APIError,
3662
+ } from 'notebooklm-kit'
3663
+
3664
+ try {
3665
+ const quiz = await sdk.artifacts.create('notebook-id', ArtifactType.QUIZ, {
3666
+ instructions: 'Create a quiz',
3667
+ customization: { numberOfQuestions: 2, difficulty: 2, language: 'en' },
3668
+ })
3669
+ } catch (error) {
3670
+ if (error instanceof NotebookLMAuthError) {
3671
+ console.error('Authentication failed - refresh your cookies')
3672
+ } else if (error instanceof RateLimitError) {
3673
+ console.error('Rate limit exceeded:', error.message)
3674
+ } else if (error instanceof APIError) {
3675
+ console.error('API error:', error.message)
3676
+ } else if (error instanceof NotebookLMError) {
3677
+ console.error('NotebookLM error:', error.message)
3678
+ }
3679
+ }
3680
+ ```
3681
+
3682
+ ## Best Practices
3683
+
3684
+ ### Resource Management
3685
+
3686
+ **Always dispose of the SDK when done** to prevent memory leaks and stop background processes:
3687
+
3688
+ ```typescript
3689
+ import { NotebookLMClient } from 'notebooklm-kit';
3690
+
3691
+ async function main() {
3692
+ const sdk = new NotebookLMClient();
3693
+
3694
+ try {
3695
+ await sdk.connect();
3696
+ // ... use SDK ...
3697
+ } finally {
3698
+ await sdk.dispose(); // Always cleanup
3699
+ }
3700
+ }
3701
+ ```
3702
+
3703
+ **Graceful shutdown for long-running applications:**
3704
+
3705
+ ```typescript
3706
+ // Handle process termination gracefully
3707
+ process.on('SIGINT', async () => {
3708
+ console.log('Shutting down...');
3709
+ await sdk.dispose();
3710
+ process.exit(0);
3711
+ });
3712
+
3713
+ process.on('SIGTERM', async () => {
3714
+ console.log('Terminating...');
3715
+ await sdk.dispose();
3716
+ process.exit(0);
3717
+ });
3718
+ ```
3719
+
3720
+ ### Error Handling
3721
+
3722
+ **Use specific error types** for better error handling:
3723
+
3724
+ ```typescript
3725
+ import {
3726
+ NotebookLMError,
3727
+ NotebookLMAuthError,
3728
+ RateLimitError,
3729
+ APIError,
3730
+ } from 'notebooklm-kit';
3731
+
3732
+ try {
3733
+ const notebook = await sdk.notebooks.create({ title: 'My Notebook' });
3734
+ } catch (error) {
3735
+ if (error instanceof NotebookLMAuthError) {
3736
+ // Authentication failed - credentials expired or invalid
3737
+ console.error('Please refresh your credentials');
3738
+ // Optionally: Force re-authentication
3739
+ // Set FORCE_REAUTH=true in .env or delete credentials.json
3740
+ } else if (error instanceof RateLimitError) {
3741
+ // Rate limit exceeded - wait before retrying
3742
+ console.error('Rate limit exceeded. Please wait before retrying.');
3743
+ // Implement exponential backoff
3744
+ } else if (error instanceof APIError) {
3745
+ // API error - check error code and message
3746
+ if (error.code === 143) {
3747
+ console.error('Resource not found');
3748
+ } else if (error.isRetryable()) {
3749
+ // Retry transient errors
3750
+ console.error('Transient error, will retry:', error.message);
3751
+ } else {
3752
+ console.error('API error:', error.message);
3753
+ }
3754
+ } else if (error instanceof NotebookLMError) {
3755
+ // Generic NotebookLM error
3756
+ console.error('NotebookLM error:', error.message);
3757
+ } else {
3758
+ // Unexpected error
3759
+ console.error('Unexpected error:', error);
3760
+ }
3761
+ }
3762
+ ```
3763
+
3764
+ **Retry logic for transient errors:**
3765
+
3766
+ ```typescript
3767
+ async function createNotebookWithRetry(title: string, maxRetries = 3) {
3768
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
3769
+ try {
3770
+ return await sdk.notebooks.create({ title });
3771
+ } catch (error) {
3772
+ if (error instanceof APIError && error.isRetryable() && attempt < maxRetries - 1) {
3773
+ const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
3774
+ console.log(`Retry ${attempt + 1}/${maxRetries} after ${delay}ms...`);
3775
+ await new Promise(resolve => setTimeout(resolve, delay));
3776
+ continue;
3777
+ }
3778
+ throw error; // Re-throw if not retryable or max retries reached
3779
+ }
3780
+ }
3781
+ }
3782
+ ```
3783
+
3784
+ ### Credential Management
3785
+
3786
+ **Use saved credentials** for faster startup (credentials are automatically saved after first auto-login):
3787
+
3788
+ ```typescript
3789
+ // First run: Auto-login saves credentials to credentials.json
3790
+ const sdk = new NotebookLMClient({
3791
+ auth: {
3792
+ email: process.env.GOOGLE_EMAIL!,
3793
+ password: process.env.GOOGLE_PASSWORD!,
3794
+ },
3795
+ });
3796
+
3797
+ await sdk.connect(); // Saves credentials for future use
3798
+
3799
+ // Subsequent runs: Credentials loaded automatically from credentials.json
3800
+ // No need to provide email/password again
3801
+ const sdk2 = new NotebookLMClient();
3802
+ await sdk2.connect(); // Uses saved credentials
3803
+ ```
3804
+
3805
+ **Force re-authentication when needed:**
3806
+
3807
+ ```typescript
3808
+ // Option 1: Set environment variable
3809
+ // FORCE_REAUTH=true
3810
+
3811
+ // Option 2: Delete credentials.json file
3812
+ // rm credentials.json
3813
+
3814
+ // Option 3: Explicitly provide new credentials
3815
+ const sdk = new NotebookLMClient({
3816
+ auth: {
3817
+ email: process.env.GOOGLE_EMAIL!,
3818
+ password: process.env.GOOGLE_PASSWORD!,
3819
+ },
3820
+ });
3821
+ ```
3822
+
3823
+ ### Quota Management
3824
+
3825
+ **Check quota before operations** to avoid rate limit errors:
3826
+
3827
+ ```typescript
3828
+ // Check remaining quota
3829
+ const remainingChats = sdk.getRemaining('chats');
3830
+ if (remainingChats <= 0) {
3831
+ console.warn('No chat quota remaining. Please wait or upgrade plan.');
3832
+ return;
3833
+ }
3834
+
3835
+ // Use chat
3836
+ const response = await sdk.generation.chat(notebookId, 'Your question');
3837
+ ```
3838
+
3839
+ **Monitor usage:**
3840
+
3841
+ ```typescript
3842
+ const usage = sdk.getUsage();
3843
+ console.log(`Notebooks: ${usage.notebooks.used}/${usage.notebooks.limit}`);
3844
+ console.log(`Chats: ${usage.chats.used}/${usage.chats.limit}`);
3845
+ console.log(`Sources: ${usage.sources.used}/${usage.sources.limit}`);
3846
+ ```
3847
+
3848
+ ### Source Processing
3849
+
3850
+ **Wait for sources to process** before creating artifacts:
3851
+
3852
+ ```typescript
3853
+ // Add source
3854
+ const sourceId = await sdk.sources.add.url(notebookId, {
3855
+ url: 'https://example.com/article',
3856
+ });
3857
+
3858
+ // Wait for processing to complete
3859
+ let status = await sdk.sources.status(notebookId);
3860
+ while (status.sources.find(s => s.sourceId === sourceId)?.state !== 'READY') {
3861
+ await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
3862
+ status = await sdk.sources.status(notebookId);
3863
+ }
3864
+
3865
+ // Now create artifact (source is ready)
3866
+ const quiz = await sdk.artifacts.create(notebookId, ArtifactType.QUIZ);
3867
+ ```
3868
+
3869
+ ### Artifact State Checking
3870
+
3871
+ **Check artifact state** before downloading or using:
3872
+
3873
+ ```typescript
3874
+ // Create artifact
3875
+ const artifact = await sdk.artifacts.create(notebookId, ArtifactType.QUIZ);
3876
+
3877
+ // Wait for artifact to be ready
3878
+ let currentArtifact = artifact;
3879
+ while (currentArtifact.state !== ArtifactState.READY) {
3880
+ if (currentArtifact.state === ArtifactState.FAILED) {
3881
+ throw new Error('Artifact generation failed');
3882
+ }
3883
+
3884
+ await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
3885
+ currentArtifact = await sdk.artifacts.get(artifact.artifactId, notebookId);
3886
+ }
3887
+
3888
+ // Now download or use the artifact
3889
+ const quizData = await sdk.artifacts.download(artifact.artifactId, './downloads', notebookId);
3890
+ ```
3891
+
3892
+ ### Async/Await Patterns
3893
+
3894
+ **Use async/await consistently** for better error handling:
3895
+
3896
+ ```typescript
3897
+ // ✅ Good: Proper async/await
3898
+ async function processNotebook(notebookId: string) {
3899
+ try {
3900
+ const sources = await sdk.sources.list(notebookId);
3901
+ const artifacts = await sdk.artifacts.list(notebookId);
3902
+ return { sources, artifacts };
3903
+ } catch (error) {
3904
+ console.error('Failed to process notebook:', error);
3905
+ throw error;
3906
+ }
3907
+ }
3908
+
3909
+ // ❌ Avoid: Mixing promises and async/await
3910
+ function processNotebookBad(notebookId: string) {
3911
+ sdk.sources.list(notebookId).then(sources => {
3912
+ // Error handling is harder here
3913
+ });
3914
+ }
3915
+ ```
3916
+
3917
+ ### Connection Lifecycle
3918
+
3919
+ **Connect once, reuse the SDK instance:**
3920
+
3921
+ ```typescript
3922
+ // ✅ Good: Connect once, reuse
3923
+ const sdk = new NotebookLMClient();
3924
+ await sdk.connect();
3925
+
3926
+ // Use SDK multiple times
3927
+ const notebooks = await sdk.notebooks.list();
3928
+ const sources = await sdk.sources.list(notebookId);
3929
+ const artifacts = await sdk.artifacts.list(notebookId);
3930
+
3931
+ await sdk.dispose(); // Cleanup when done
3932
+
3933
+ // ❌ Avoid: Connecting multiple times
3934
+ // Don't call connect() multiple times - reuse the same instance
3935
+ ```
3936
+
3937
+ ### Debug Mode
3938
+
3939
+ **Enable debug mode for troubleshooting:**
3940
+
3941
+ ```typescript
3942
+ // In development
3943
+ const sdk = new NotebookLMClient({
3944
+ debug: process.env.NODE_ENV === 'development',
3945
+ });
3946
+
3947
+ // Or via environment variable
3948
+ // NOTEBOOKLM_DEBUG=true
3949
+
3950
+ // Debug mode shows:
3951
+ // - RPC call details
3952
+ // - Authentication flow
3953
+ // - Auto-refresh operations
3954
+ // - Error details
3955
+ // - Response parsing
3956
+ ```
3957
+
3958
+ ### Batch Operations
3959
+
3960
+ **Use batch operations** when adding multiple sources:
3961
+
3962
+ ```typescript
3963
+ // ✅ Good: Batch add sources
3964
+ await sdk.sources.add.batch(notebookId, {
3965
+ sources: [
3966
+ { type: 'url', url: 'https://example.com/1' },
3967
+ { type: 'url', url: 'https://example.com/2' },
3968
+ { type: 'url', url: 'https://example.com/3' },
3969
+ ],
3970
+ });
3971
+
3972
+ // ❌ Avoid: Adding sources one by one
3973
+ // This is slower and uses more API calls
3974
+ ```
3975
+
3976
+ ### Streaming Responses
3977
+
3978
+ **Use streaming for long responses** to show progress:
3979
+
3980
+ ```typescript
3981
+ // Stream chat response for better UX
3982
+ const stream = await sdk.generation.chatStream(notebookId, 'Long question...');
3983
+
3984
+ for await (const chunk of stream) {
3985
+ if (chunk.type === 'content') {
3986
+ process.stdout.write(chunk.content); // Show progress
3987
+ } else if (chunk.type === 'citations') {
3988
+ console.log('\nCitations:', chunk.citations);
3989
+ }
3990
+ }
3991
+ ```
3992
+
3993
+ ### Environment Variables
3994
+
3995
+ **Use environment variables** for configuration:
3996
+
3997
+ ```typescript
3998
+ // ✅ Good: Use .env file
3999
+ // .env
4000
+ NOTEBOOKLM_AUTH_TOKEN=...
4001
+ NOTEBOOKLM_COOKIES=...
4002
+ NOTEBOOKLM_DEBUG=true
4003
+
4004
+ // ❌ Avoid: Hardcoding credentials
4005
+ const sdk = new NotebookLMClient({
4006
+ authToken: 'hardcoded-token', // Don't do this!
4007
+ });
4008
+ ```
4009
+
4010
+ ### Recommended Patterns
4011
+
4012
+ **Complete example with best practices:**
4013
+
4014
+ ```typescript
4015
+ import { NotebookLMClient, ArtifactType, ArtifactState } from 'notebooklm-kit';
4016
+ import dotenv from 'dotenv';
4017
+
4018
+ dotenv.config();
4019
+
4020
+ async function main() {
4021
+ const sdk = new NotebookLMClient({
4022
+ debug: process.env.NOTEBOOKLM_DEBUG === 'true',
4023
+ });
4024
+
4025
+ try {
4026
+ await sdk.connect();
4027
+
4028
+ // Check quota before operations
4029
+ const remaining = sdk.getRemaining('chats');
4030
+ if (remaining <= 0) {
4031
+ console.warn('No chat quota remaining');
4032
+ return;
4033
+ }
4034
+
4035
+ // Create notebook
4036
+ const notebook = await sdk.notebooks.create({
4037
+ title: 'Research Project',
4038
+ emoji: '📚',
4039
+ });
4040
+
4041
+ // Add source and wait for processing
4042
+ const sourceId = await sdk.sources.add.url(notebook.projectId, {
4043
+ url: 'https://example.com/article',
4044
+ });
4045
+
4046
+ // Wait for source to be ready
4047
+ let status = await sdk.sources.status(notebook.projectId);
4048
+ while (status.sources.find(s => s.sourceId === sourceId)?.state !== 'READY') {
4049
+ await new Promise(resolve => setTimeout(resolve, 2000));
4050
+ status = await sdk.sources.status(notebook.projectId);
4051
+ }
4052
+
4053
+ // Create artifact and wait for completion
4054
+ const artifact = await sdk.artifacts.create(
4055
+ notebook.projectId,
4056
+ ArtifactType.QUIZ,
4057
+ {
4058
+ customization: {
4059
+ numberOfQuestions: 10,
4060
+ difficulty: 2,
4061
+ },
4062
+ }
4063
+ );
4064
+
4065
+ // Wait for artifact to be ready
4066
+ let currentArtifact = artifact;
4067
+ while (currentArtifact.state !== ArtifactState.READY) {
4068
+ if (currentArtifact.state === ArtifactState.FAILED) {
4069
+ throw new Error('Artifact generation failed');
4070
+ }
4071
+ await new Promise(resolve => setTimeout(resolve, 2000));
4072
+ currentArtifact = await sdk.artifacts.get(
4073
+ artifact.artifactId,
4074
+ notebook.projectId
4075
+ );
4076
+ }
4077
+
4078
+ // Download artifact
4079
+ const quizData = await sdk.artifacts.download(
4080
+ artifact.artifactId,
4081
+ './downloads',
4082
+ notebook.projectId
4083
+ );
4084
+
4085
+ console.log('Success!', quizData);
4086
+
4087
+ } catch (error) {
4088
+ console.error('Error:', error);
4089
+ process.exit(1);
4090
+ } finally {
4091
+ await sdk.dispose(); // Always cleanup
4092
+ }
4093
+ }
4094
+
4095
+ // Graceful shutdown
4096
+ process.on('SIGINT', async () => {
4097
+ console.log('\nShutting down...');
4098
+ process.exit(0);
4099
+ });
4100
+
4101
+ main();
4102
+ ```