notebooklm-sdk 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -280,11 +280,19 @@ interface Note {
280
280
  createdAt: Date | null;
281
281
  updatedAt: Date | null;
282
282
  }
283
- interface MindMap {
284
- id: string;
285
- title: string | null;
286
- content: string;
287
- createdAt: Date | null;
283
+
284
+ declare class NotesAPI {
285
+ private readonly rpc;
286
+ constructor(rpc: RPCCore);
287
+ list(notebookId: string): Promise<Note[]>;
288
+ listMindMaps(notebookId: string): Promise<Note[]>;
289
+ create(notebookId: string, content: string, title?: string): Promise<Note>;
290
+ update(notebookId: string, noteId: string, content: string, title?: string): Promise<Note>;
291
+ delete(notebookId: string, noteId: string): Promise<boolean>;
292
+ private _fetchAll;
293
+ private _isMindMap;
294
+ private _extractContent;
295
+ private _parseItem;
288
296
  }
289
297
 
290
298
  interface CreateAudioOptions {
@@ -322,6 +330,15 @@ interface CreateSlideDeckOptions {
322
330
  instructions?: string;
323
331
  language?: string;
324
332
  }
333
+ interface CreateDataTableOptions {
334
+ sourceIds?: string[];
335
+ instructions?: string;
336
+ language?: string;
337
+ }
338
+ interface DataTableContent {
339
+ headers: string[];
340
+ rows: string[][];
341
+ }
325
342
  type ReportFormat = "briefing_doc" | "study_guide" | "blog_post" | "custom";
326
343
  interface CreateReportOptions {
327
344
  format?: ReportFormat;
@@ -333,8 +350,10 @@ interface CreateReportOptions {
333
350
  declare class ArtifactsAPI {
334
351
  private readonly rpc;
335
352
  private readonly auth;
336
- constructor(rpc: RPCCore, auth: AuthTokens);
353
+ private readonly notes;
354
+ constructor(rpc: RPCCore, auth: AuthTokens, notes: NotesAPI);
337
355
  list(notebookId: string): Promise<Artifact[]>;
356
+ private _listRaw;
338
357
  get(notebookId: string, artifactId: string): Promise<Artifact | null>;
339
358
  delete(notebookId: string, artifactId: string): Promise<boolean>;
340
359
  rename(notebookId: string, artifactId: string, newTitle: string): Promise<boolean>;
@@ -344,8 +363,9 @@ declare class ArtifactsAPI {
344
363
  createFlashcards(notebookId: string, opts?: CreateQuizOptions): Promise<GenerationStatus>;
345
364
  createInfographic(notebookId: string, opts?: CreateInfographicOptions): Promise<GenerationStatus>;
346
365
  createSlideDeck(notebookId: string, opts?: CreateSlideDeckOptions): Promise<GenerationStatus>;
366
+ createDataTable(notebookId: string, opts?: CreateDataTableOptions): Promise<GenerationStatus>;
347
367
  createReport(notebookId: string, opts?: CreateReportOptions): Promise<GenerationStatus>;
348
- createMindMap(notebookId: string, sourceIds?: string[]): Promise<GenerationStatus>;
368
+ createMindMap(notebookId: string, sourceIds?: string[]): Promise<Note>;
349
369
  /** Poll until artifact reaches completed/failed status. */
350
370
  waitUntilReady(notebookId: string, artifactId: string, timeout?: number, pollInterval?: number): Promise<Artifact>;
351
371
  /** Download audio content as a Buffer. */
@@ -356,6 +376,12 @@ declare class ArtifactsAPI {
356
376
  getReportMarkdown(notebookId: string, artifactId: string): Promise<string | null>;
357
377
  /** Get interactive HTML for quiz/flashcard artifacts. */
358
378
  getInteractiveHtml(notebookId: string, artifactId: string): Promise<string | null>;
379
+ /** Download a completed slide deck as PDF or PPTX. Returns a Buffer. */
380
+ downloadSlideDeck(notebookId: string, artifactId: string, format?: "pdf" | "pptx"): Promise<Buffer>;
381
+ /** Download a completed infographic as PNG. Returns a Buffer. */
382
+ downloadInfographic(notebookId: string, artifactId: string): Promise<Buffer>;
383
+ /** Get parsed headers and rows from a completed data table artifact. */
384
+ getDataTableContent(notebookId: string, artifactId: string): Promise<DataTableContent | null>;
359
385
  /**
360
386
  * Fetch a Google-hosted media URL, manually following redirects to ensure
361
387
  * cookies are included on every hop. Node/Bun fetch strips the Cookie header
@@ -395,18 +421,6 @@ declare class NotebooksAPI {
395
421
  getDescription(notebookId: string): Promise<NotebookDescription>;
396
422
  }
397
423
 
398
- declare class NotesAPI {
399
- private readonly rpc;
400
- constructor(rpc: RPCCore);
401
- list(notebookId: string): Promise<{
402
- notes: Note[];
403
- mindMaps: MindMap[];
404
- }>;
405
- create(notebookId: string, content: string, title?: string): Promise<Note>;
406
- update(notebookId: string, noteId: string, content: string, title?: string): Promise<Note>;
407
- delete(notebookId: string, noteId: string): Promise<boolean>;
408
- }
409
-
410
424
  interface ResearchTask {
411
425
  taskId: string;
412
426
  reportId: string | null;
@@ -553,4 +567,4 @@ declare class NotebookLMClient {
553
567
  refreshTokens(): Promise<void>;
554
568
  }
555
569
 
556
- export { type AddSourceOptions, type Artifact, type ArtifactStatus, type ArtifactType, ArtifactTypeCode, ArtifactsAPI, type AskOptions, type AskResult, AudioFormat, type AudioFormatValue, AudioLength, type AudioLengthValue, AuthTokens, ChatAPI, type ChatReference, type ClientOptions, ConnectOptions, type ConversationTurn, type CreateAudioOptions, type CreateInfographicOptions, type CreateQuizOptions, type CreateReportOptions, type CreateSlideDeckOptions, type CreateVideoOptions, ExportType, type ExportTypeValue, type GenerationStatus, type ImportedSource, InfographicDetail, type InfographicDetailValue, InfographicOrientation, type InfographicOrientationValue, InfographicStyle, type InfographicStyleValue, type MindMap, type Note, type Notebook, type NotebookDescription, NotebookLMClient, type NotebookMetadata, NotebooksAPI, NotesAPI, QuizDifficulty, type QuizDifficultyValue, QuizQuantity, type QuizQuantityValue, RPCMethod, type RPCMethodId, ResearchAPI, type ResearchResult, type ResearchSource, type ResearchTask, SettingsAPI, ShareAccess, type ShareAccessValue, SharePermission, type SharePermissionValue, type ShareStatus, ShareViewLevel, type ShareViewLevelValue, type SharedUser, SharingAPI, SlideDeckFormat, type SlideDeckFormatValue, SlideDeckLength, type SlideDeckLengthValue, type Source, type SourceStatus, type SourceSummary, type SourceType, SourcesAPI, type SuggestedTopic, VideoFormat, type VideoFormatValue, VideoStyle, type VideoStyleValue };
570
+ export { type AddSourceOptions, type Artifact, type ArtifactStatus, type ArtifactType, ArtifactTypeCode, ArtifactsAPI, type AskOptions, type AskResult, AudioFormat, type AudioFormatValue, AudioLength, type AudioLengthValue, AuthTokens, ChatAPI, type ChatReference, type ClientOptions, ConnectOptions, type ConversationTurn, type CreateAudioOptions, type CreateDataTableOptions, type CreateInfographicOptions, type CreateQuizOptions, type CreateReportOptions, type CreateSlideDeckOptions, type CreateVideoOptions, type DataTableContent, ExportType, type ExportTypeValue, type GenerationStatus, type ImportedSource, InfographicDetail, type InfographicDetailValue, InfographicOrientation, type InfographicOrientationValue, InfographicStyle, type InfographicStyleValue, type Note, type Notebook, type NotebookDescription, NotebookLMClient, type NotebookMetadata, NotebooksAPI, NotesAPI, QuizDifficulty, type QuizDifficultyValue, QuizQuantity, type QuizQuantityValue, RPCMethod, type RPCMethodId, ResearchAPI, type ResearchResult, type ResearchSource, type ResearchTask, SettingsAPI, ShareAccess, type ShareAccessValue, SharePermission, type SharePermissionValue, type ShareStatus, ShareViewLevel, type ShareViewLevelValue, type SharedUser, SharingAPI, SlideDeckFormat, type SlideDeckFormatValue, SlideDeckLength, type SlideDeckLengthValue, type Source, type SourceStatus, type SourceSummary, type SourceType, SourcesAPI, type SuggestedTopic, VideoFormat, type VideoFormatValue, VideoStyle, type VideoStyleValue };
package/dist/index.d.ts CHANGED
@@ -280,11 +280,19 @@ interface Note {
280
280
  createdAt: Date | null;
281
281
  updatedAt: Date | null;
282
282
  }
283
- interface MindMap {
284
- id: string;
285
- title: string | null;
286
- content: string;
287
- createdAt: Date | null;
283
+
284
+ declare class NotesAPI {
285
+ private readonly rpc;
286
+ constructor(rpc: RPCCore);
287
+ list(notebookId: string): Promise<Note[]>;
288
+ listMindMaps(notebookId: string): Promise<Note[]>;
289
+ create(notebookId: string, content: string, title?: string): Promise<Note>;
290
+ update(notebookId: string, noteId: string, content: string, title?: string): Promise<Note>;
291
+ delete(notebookId: string, noteId: string): Promise<boolean>;
292
+ private _fetchAll;
293
+ private _isMindMap;
294
+ private _extractContent;
295
+ private _parseItem;
288
296
  }
289
297
 
290
298
  interface CreateAudioOptions {
@@ -322,6 +330,15 @@ interface CreateSlideDeckOptions {
322
330
  instructions?: string;
323
331
  language?: string;
324
332
  }
333
+ interface CreateDataTableOptions {
334
+ sourceIds?: string[];
335
+ instructions?: string;
336
+ language?: string;
337
+ }
338
+ interface DataTableContent {
339
+ headers: string[];
340
+ rows: string[][];
341
+ }
325
342
  type ReportFormat = "briefing_doc" | "study_guide" | "blog_post" | "custom";
326
343
  interface CreateReportOptions {
327
344
  format?: ReportFormat;
@@ -333,8 +350,10 @@ interface CreateReportOptions {
333
350
  declare class ArtifactsAPI {
334
351
  private readonly rpc;
335
352
  private readonly auth;
336
- constructor(rpc: RPCCore, auth: AuthTokens);
353
+ private readonly notes;
354
+ constructor(rpc: RPCCore, auth: AuthTokens, notes: NotesAPI);
337
355
  list(notebookId: string): Promise<Artifact[]>;
356
+ private _listRaw;
338
357
  get(notebookId: string, artifactId: string): Promise<Artifact | null>;
339
358
  delete(notebookId: string, artifactId: string): Promise<boolean>;
340
359
  rename(notebookId: string, artifactId: string, newTitle: string): Promise<boolean>;
@@ -344,8 +363,9 @@ declare class ArtifactsAPI {
344
363
  createFlashcards(notebookId: string, opts?: CreateQuizOptions): Promise<GenerationStatus>;
345
364
  createInfographic(notebookId: string, opts?: CreateInfographicOptions): Promise<GenerationStatus>;
346
365
  createSlideDeck(notebookId: string, opts?: CreateSlideDeckOptions): Promise<GenerationStatus>;
366
+ createDataTable(notebookId: string, opts?: CreateDataTableOptions): Promise<GenerationStatus>;
347
367
  createReport(notebookId: string, opts?: CreateReportOptions): Promise<GenerationStatus>;
348
- createMindMap(notebookId: string, sourceIds?: string[]): Promise<GenerationStatus>;
368
+ createMindMap(notebookId: string, sourceIds?: string[]): Promise<Note>;
349
369
  /** Poll until artifact reaches completed/failed status. */
350
370
  waitUntilReady(notebookId: string, artifactId: string, timeout?: number, pollInterval?: number): Promise<Artifact>;
351
371
  /** Download audio content as a Buffer. */
@@ -356,6 +376,12 @@ declare class ArtifactsAPI {
356
376
  getReportMarkdown(notebookId: string, artifactId: string): Promise<string | null>;
357
377
  /** Get interactive HTML for quiz/flashcard artifacts. */
358
378
  getInteractiveHtml(notebookId: string, artifactId: string): Promise<string | null>;
379
+ /** Download a completed slide deck as PDF or PPTX. Returns a Buffer. */
380
+ downloadSlideDeck(notebookId: string, artifactId: string, format?: "pdf" | "pptx"): Promise<Buffer>;
381
+ /** Download a completed infographic as PNG. Returns a Buffer. */
382
+ downloadInfographic(notebookId: string, artifactId: string): Promise<Buffer>;
383
+ /** Get parsed headers and rows from a completed data table artifact. */
384
+ getDataTableContent(notebookId: string, artifactId: string): Promise<DataTableContent | null>;
359
385
  /**
360
386
  * Fetch a Google-hosted media URL, manually following redirects to ensure
361
387
  * cookies are included on every hop. Node/Bun fetch strips the Cookie header
@@ -395,18 +421,6 @@ declare class NotebooksAPI {
395
421
  getDescription(notebookId: string): Promise<NotebookDescription>;
396
422
  }
397
423
 
398
- declare class NotesAPI {
399
- private readonly rpc;
400
- constructor(rpc: RPCCore);
401
- list(notebookId: string): Promise<{
402
- notes: Note[];
403
- mindMaps: MindMap[];
404
- }>;
405
- create(notebookId: string, content: string, title?: string): Promise<Note>;
406
- update(notebookId: string, noteId: string, content: string, title?: string): Promise<Note>;
407
- delete(notebookId: string, noteId: string): Promise<boolean>;
408
- }
409
-
410
424
  interface ResearchTask {
411
425
  taskId: string;
412
426
  reportId: string | null;
@@ -553,4 +567,4 @@ declare class NotebookLMClient {
553
567
  refreshTokens(): Promise<void>;
554
568
  }
555
569
 
556
- export { type AddSourceOptions, type Artifact, type ArtifactStatus, type ArtifactType, ArtifactTypeCode, ArtifactsAPI, type AskOptions, type AskResult, AudioFormat, type AudioFormatValue, AudioLength, type AudioLengthValue, AuthTokens, ChatAPI, type ChatReference, type ClientOptions, ConnectOptions, type ConversationTurn, type CreateAudioOptions, type CreateInfographicOptions, type CreateQuizOptions, type CreateReportOptions, type CreateSlideDeckOptions, type CreateVideoOptions, ExportType, type ExportTypeValue, type GenerationStatus, type ImportedSource, InfographicDetail, type InfographicDetailValue, InfographicOrientation, type InfographicOrientationValue, InfographicStyle, type InfographicStyleValue, type MindMap, type Note, type Notebook, type NotebookDescription, NotebookLMClient, type NotebookMetadata, NotebooksAPI, NotesAPI, QuizDifficulty, type QuizDifficultyValue, QuizQuantity, type QuizQuantityValue, RPCMethod, type RPCMethodId, ResearchAPI, type ResearchResult, type ResearchSource, type ResearchTask, SettingsAPI, ShareAccess, type ShareAccessValue, SharePermission, type SharePermissionValue, type ShareStatus, ShareViewLevel, type ShareViewLevelValue, type SharedUser, SharingAPI, SlideDeckFormat, type SlideDeckFormatValue, SlideDeckLength, type SlideDeckLengthValue, type Source, type SourceStatus, type SourceSummary, type SourceType, SourcesAPI, type SuggestedTopic, VideoFormat, type VideoFormatValue, VideoStyle, type VideoStyleValue };
570
+ export { type AddSourceOptions, type Artifact, type ArtifactStatus, type ArtifactType, ArtifactTypeCode, ArtifactsAPI, type AskOptions, type AskResult, AudioFormat, type AudioFormatValue, AudioLength, type AudioLengthValue, AuthTokens, ChatAPI, type ChatReference, type ClientOptions, ConnectOptions, type ConversationTurn, type CreateAudioOptions, type CreateDataTableOptions, type CreateInfographicOptions, type CreateQuizOptions, type CreateReportOptions, type CreateSlideDeckOptions, type CreateVideoOptions, type DataTableContent, ExportType, type ExportTypeValue, type GenerationStatus, type ImportedSource, InfographicDetail, type InfographicDetailValue, InfographicOrientation, type InfographicOrientationValue, InfographicStyle, type InfographicStyleValue, type Note, type Notebook, type NotebookDescription, NotebookLMClient, type NotebookMetadata, NotebooksAPI, NotesAPI, QuizDifficulty, type QuizDifficultyValue, QuizQuantity, type QuizQuantityValue, RPCMethod, type RPCMethodId, ResearchAPI, type ResearchResult, type ResearchSource, type ResearchTask, SettingsAPI, ShareAccess, type ShareAccessValue, SharePermission, type SharePermissionValue, type ShareStatus, ShareViewLevel, type ShareViewLevelValue, type SharedUser, SharingAPI, SlideDeckFormat, type SlideDeckFormatValue, SlideDeckLength, type SlideDeckLengthValue, type Source, type SourceStatus, type SourceSummary, type SourceType, SourcesAPI, type SuggestedTopic, VideoFormat, type VideoFormatValue, VideoStyle, type VideoStyleValue };
package/dist/index.js CHANGED
@@ -453,10 +453,8 @@ function loadCookiesFromFile(filePath) {
453
453
  try {
454
454
  raw = readFileSync(filePath, "utf-8");
455
455
  } catch {
456
- throw new AuthError(
457
- `Session file not found: ${filePath}
458
- Run: npx notebooklm-sdk login`
459
- );
456
+ throw new AuthError(`Session file not found: ${filePath}
457
+ Run: npx notebooklm-sdk login`);
460
458
  }
461
459
  return extractCookiesFromStorageState(JSON.parse(raw));
462
460
  }
@@ -590,9 +588,7 @@ async function connect(opts = {}) {
590
588
  } else if (envCookies) {
591
589
  cookieMap = loadCookiesFromString(envCookies);
592
590
  } else {
593
- throw new AuthError(
594
- "No session found. Run: npx notebooklm-sdk login"
595
- );
591
+ throw new AuthError("No session found. Run: npx notebooklm-sdk login");
596
592
  }
597
593
  }
598
594
  const { csrfToken, sessionId } = await fetchTokens(cookieMap);
@@ -727,26 +723,6 @@ function parseArtifact(data, notebookId) {
727
723
  _raw: Array.isArray(data) ? data : []
728
724
  };
729
725
  }
730
- function parseNote(data) {
731
- const id = typeof data[0] === "string" ? data[0] : "";
732
- const content = typeof data[1] === "string" ? data[1] : "";
733
- const title = typeof data[2] === "string" ? data[2] : null;
734
- let createdAt = null;
735
- let updatedAt = null;
736
- if (Array.isArray(data[3]) && typeof data[3][0] === "number") {
737
- try {
738
- createdAt = new Date(data[3][0] * 1e3);
739
- } catch {
740
- }
741
- }
742
- if (Array.isArray(data[4]) && typeof data[4][0] === "number") {
743
- try {
744
- updatedAt = new Date(data[4][0] * 1e3);
745
- } catch {
746
- }
747
- }
748
- return { id, title, content, createdAt, updatedAt };
749
- }
750
726
 
751
727
  // src/api/artifacts.ts
752
728
  function tripleNest(ids) {
@@ -756,18 +732,13 @@ function doubleNest(ids) {
756
732
  return ids.map((id) => [id]);
757
733
  }
758
734
  var ArtifactsAPI = class {
759
- constructor(rpc, auth) {
735
+ constructor(rpc, auth, notes) {
760
736
  this.rpc = rpc;
761
737
  this.auth = auth;
738
+ this.notes = notes;
762
739
  }
763
740
  async list(notebookId) {
764
- const params = [[2], notebookId, 'NOT artifact.status = "ARTIFACT_STATUS_SUGGESTED"'];
765
- const result = await this.rpc.call(RPCMethod.LIST_ARTIFACTS, params, {
766
- sourcePath: `/notebook/${notebookId}`,
767
- allowNull: true
768
- });
769
- if (!Array.isArray(result) || !result.length) return [];
770
- const rawList = Array.isArray(result[0]) ? result[0] : result;
741
+ const rawList = await this._listRaw(notebookId);
771
742
  const artifacts = [];
772
743
  for (const item of rawList) {
773
744
  if (Array.isArray(item)) {
@@ -779,6 +750,15 @@ var ArtifactsAPI = class {
779
750
  }
780
751
  return artifacts;
781
752
  }
753
+ async _listRaw(notebookId) {
754
+ const params = [[2], notebookId, 'NOT artifact.status = "ARTIFACT_STATUS_SUGGESTED"'];
755
+ const result = await this.rpc.call(RPCMethod.LIST_ARTIFACTS, params, {
756
+ sourcePath: `/notebook/${notebookId}`,
757
+ allowNull: true
758
+ });
759
+ if (!Array.isArray(result) || !result.length) return [];
760
+ return Array.isArray(result[0]) ? result[0] : result;
761
+ }
782
762
  async get(notebookId, artifactId) {
783
763
  const artifacts = await this.list(notebookId);
784
764
  return artifacts.find((a) => a.id === artifactId) ?? null;
@@ -958,6 +938,37 @@ var ArtifactsAPI = class {
958
938
  ];
959
939
  return this._callGenerate(notebookId, params);
960
940
  }
941
+ async createDataTable(notebookId, opts = {}) {
942
+ const language = opts.language ?? "en";
943
+ const sourceIds = opts.sourceIds ?? await this.rpc.getSourceIds(notebookId);
944
+ const triple = tripleNest(sourceIds);
945
+ const params = [
946
+ [2],
947
+ notebookId,
948
+ [
949
+ null,
950
+ null,
951
+ ArtifactTypeCode.DATA_TABLE,
952
+ triple,
953
+ null,
954
+ null,
955
+ null,
956
+ null,
957
+ null,
958
+ null,
959
+ null,
960
+ null,
961
+ null,
962
+ null,
963
+ null,
964
+ null,
965
+ null,
966
+ null,
967
+ [null, [opts.instructions ?? null, language]]
968
+ ]
969
+ ];
970
+ return this._callGenerate(notebookId, params);
971
+ }
961
972
  async createReport(notebookId, opts = {}) {
962
973
  const format = opts.format ?? "briefing_doc";
963
974
  const language = opts.language ?? "en";
@@ -1023,7 +1034,15 @@ ${opts.extraInstructions}` : cfg.prompt;
1023
1034
  sourcePath: `/notebook/${notebookId}`,
1024
1035
  allowNull: true
1025
1036
  });
1026
- return this._parseGenerationResult(result);
1037
+ const mindMapJson = Array.isArray(result) && Array.isArray(result[0]) && typeof result[0][0] === "string" ? result[0][0] : null;
1038
+ if (!mindMapJson) throw new Error("Mind map generation returned no content");
1039
+ let title = "Mind Map";
1040
+ try {
1041
+ const parsed = JSON.parse(mindMapJson);
1042
+ if (typeof parsed["name"] === "string") title = parsed["name"];
1043
+ } catch {
1044
+ }
1045
+ return this.notes.create(notebookId, mindMapJson, title);
1027
1046
  }
1028
1047
  // ---------------------------------------------------------------------------
1029
1048
  // Polling / download
@@ -1079,6 +1098,48 @@ ${opts.extraInstructions}` : cfg.prompt;
1079
1098
  }
1080
1099
  return null;
1081
1100
  }
1101
+ /** Download a completed slide deck as PDF or PPTX. Returns a Buffer. */
1102
+ async downloadSlideDeck(notebookId, artifactId, format = "pdf") {
1103
+ const rawList = await this._listRaw(notebookId);
1104
+ const raw = rawList.find(
1105
+ (a) => a[0] === artifactId && a[2] === ArtifactTypeCode.SLIDE_DECK
1106
+ );
1107
+ if (!raw) throw new ArtifactNotReadyError("slide_deck", { artifactId });
1108
+ const metadata = raw[16];
1109
+ if (!Array.isArray(metadata)) throw new ArtifactNotReadyError("slide_deck", { artifactId });
1110
+ const url = format === "pptx" ? metadata[4] : metadata[3];
1111
+ if (typeof url !== "string" || !url.startsWith("http")) {
1112
+ throw new ArtifactNotReadyError("slide_deck", { artifactId, status: `no ${format} url` });
1113
+ }
1114
+ return this._fetchMediaWithCookies(url);
1115
+ }
1116
+ /** Download a completed infographic as PNG. Returns a Buffer. */
1117
+ async downloadInfographic(notebookId, artifactId) {
1118
+ const rawList = await this._listRaw(notebookId);
1119
+ const raw = rawList.find(
1120
+ (a) => a[0] === artifactId && a[2] === ArtifactTypeCode.INFOGRAPHIC
1121
+ );
1122
+ if (!raw) throw new ArtifactNotReadyError("infographic", { artifactId });
1123
+ let url = null;
1124
+ for (let i = raw.length - 1; i >= 0; i--) {
1125
+ const item = raw[i];
1126
+ if (Array.isArray(item) && Array.isArray(item[2]) && Array.isArray(item[2][0]) && Array.isArray(item[2][0][1]) && typeof item[2][0][1][0] === "string" && item[2][0][1][0].startsWith("http")) {
1127
+ url = item[2][0][1][0];
1128
+ break;
1129
+ }
1130
+ }
1131
+ if (!url) throw new ArtifactNotReadyError("infographic", { artifactId });
1132
+ return this._fetchMediaWithCookies(url);
1133
+ }
1134
+ /** Get parsed headers and rows from a completed data table artifact. */
1135
+ async getDataTableContent(notebookId, artifactId) {
1136
+ const artifacts = await this._listRaw(notebookId);
1137
+ const raw = artifacts.find(
1138
+ (a) => Array.isArray(a) && a[0] === artifactId && a[2] === ArtifactTypeCode.DATA_TABLE
1139
+ );
1140
+ if (!raw || !Array.isArray(raw) || !Array.isArray(raw[18])) return null;
1141
+ return parseDataTable(raw[18]);
1142
+ }
1082
1143
  // ---------------------------------------------------------------------------
1083
1144
  // Internal
1084
1145
  // ---------------------------------------------------------------------------
@@ -1135,6 +1196,34 @@ ${opts.extraInstructions}` : cfg.prompt;
1135
1196
  return { artifactId: null, status: "failed" };
1136
1197
  }
1137
1198
  };
1199
+ function extractCellText(cell) {
1200
+ if (typeof cell === "string") return cell;
1201
+ if (typeof cell === "number") return "";
1202
+ if (Array.isArray(cell)) return cell.map(extractCellText).join("");
1203
+ return "";
1204
+ }
1205
+ function parseDataTable(rawData) {
1206
+ try {
1207
+ const nav = rawData;
1208
+ const rowsArray = nav[0][0][0][0][4][2];
1209
+ if (!rowsArray?.length) throw new Error("Empty data table");
1210
+ const headers = [];
1211
+ const rows = [];
1212
+ for (let i = 0; i < rowsArray.length; i++) {
1213
+ const rowSection = rowsArray[i];
1214
+ if (!Array.isArray(rowSection) || rowSection.length < 3) continue;
1215
+ const cellArray = rowSection[2];
1216
+ if (!Array.isArray(cellArray)) continue;
1217
+ const values = cellArray.map(extractCellText);
1218
+ if (i === 0) headers.push(...values);
1219
+ else rows.push(values);
1220
+ }
1221
+ if (!headers.length) throw new Error("No headers found");
1222
+ return { headers, rows };
1223
+ } catch (e) {
1224
+ throw new Error(`Failed to parse data table: ${e}`);
1225
+ }
1226
+ }
1138
1227
  function sleep(ms) {
1139
1228
  return new Promise((resolve) => setTimeout(resolve, ms));
1140
1229
  }
@@ -1471,61 +1560,69 @@ var NotesAPI = class {
1471
1560
  this.rpc = rpc;
1472
1561
  }
1473
1562
  async list(notebookId) {
1474
- const params = [notebookId, [2]];
1475
- const result = await this.rpc.call(RPCMethod.GET_NOTES_AND_MIND_MAPS, params, {
1476
- sourcePath: `/notebook/${notebookId}`
1477
- });
1478
- const notes = [];
1479
- const mindMaps = [];
1480
- if (!Array.isArray(result)) return { notes, mindMaps };
1481
- try {
1482
- const notesData = result[0];
1483
- if (Array.isArray(notesData)) {
1484
- for (const n of notesData) {
1485
- if (Array.isArray(n)) notes.push(parseNote(n));
1486
- }
1487
- }
1488
- const mapsData = result[1];
1489
- if (Array.isArray(mapsData)) {
1490
- for (const m of mapsData) {
1491
- if (Array.isArray(m)) {
1492
- mindMaps.push({
1493
- id: typeof m[0] === "string" ? m[0] : "",
1494
- title: typeof m[2] === "string" ? m[2] : null,
1495
- content: typeof m[1] === "string" ? m[1] : "",
1496
- createdAt: Array.isArray(m[3]) && typeof m[3][0] === "number" ? new Date(m[3][0] * 1e3) : null
1497
- });
1498
- }
1499
- }
1500
- }
1501
- } catch {
1502
- }
1503
- return { notes, mindMaps };
1563
+ const all = await this._fetchAll(notebookId);
1564
+ return all.filter((n) => !this._isMindMap(n.content));
1565
+ }
1566
+ async listMindMaps(notebookId) {
1567
+ const all = await this._fetchAll(notebookId);
1568
+ return all.filter((n) => this._isMindMap(n.content));
1504
1569
  }
1505
1570
  async create(notebookId, content, title) {
1506
- const params = [notebookId, content, title ?? null, [2]];
1507
- const result = await this.rpc.call(RPCMethod.CREATE_NOTE, params, {
1508
- sourcePath: `/notebook/${notebookId}`
1571
+ const createParams = [notebookId, "", [1], null, "New Note"];
1572
+ const result = await this.rpc.call(RPCMethod.CREATE_NOTE, createParams, {
1573
+ sourcePath: `/notebook/${notebookId}`,
1574
+ allowNull: true
1509
1575
  });
1510
- if (Array.isArray(result)) return parseNote(result);
1511
- throw new Error("Could not parse note creation response");
1576
+ const noteId = Array.isArray(result) && Array.isArray(result[0]) && typeof result[0][0] === "string" ? result[0][0] : Array.isArray(result) && typeof result[0] === "string" ? result[0] : null;
1577
+ if (!noteId) throw new Error("CREATE_NOTE did not return a note ID");
1578
+ await this.update(notebookId, noteId, content, title ?? "New Note");
1579
+ return { id: noteId, title: title ?? null, content, createdAt: null, updatedAt: /* @__PURE__ */ new Date() };
1512
1580
  }
1513
1581
  async update(notebookId, noteId, content, title) {
1514
- const params = [notebookId, noteId, content, title ?? null, [2]];
1515
- const result = await this.rpc.call(RPCMethod.UPDATE_NOTE, params, {
1516
- sourcePath: `/notebook/${notebookId}`
1582
+ const params = [notebookId, noteId, [[[content, title ?? "New Note", [], 0]]]];
1583
+ await this.rpc.call(RPCMethod.UPDATE_NOTE, params, {
1584
+ sourcePath: `/notebook/${notebookId}`,
1585
+ allowNull: true
1517
1586
  });
1518
- if (Array.isArray(result)) return parseNote(result);
1519
1587
  return { id: noteId, title: title ?? null, content, createdAt: null, updatedAt: /* @__PURE__ */ new Date() };
1520
1588
  }
1521
1589
  async delete(notebookId, noteId) {
1522
- const params = [notebookId, noteId, [2]];
1590
+ const params = [notebookId, null, [noteId]];
1523
1591
  await this.rpc.call(RPCMethod.DELETE_NOTE, params, {
1524
1592
  sourcePath: `/notebook/${notebookId}`,
1525
1593
  allowNull: true
1526
1594
  });
1527
1595
  return true;
1528
1596
  }
1597
+ async _fetchAll(notebookId) {
1598
+ const result = await this.rpc.call(RPCMethod.GET_NOTES_AND_MIND_MAPS, [notebookId], {
1599
+ sourcePath: `/notebook/${notebookId}`,
1600
+ allowNull: true
1601
+ });
1602
+ if (!Array.isArray(result) || !Array.isArray(result[0])) return [];
1603
+ const notes = [];
1604
+ for (const item of result[0]) {
1605
+ if (!Array.isArray(item) || typeof item[0] !== "string") continue;
1606
+ if (item[1] === null && item[2] === 2) continue;
1607
+ const content = this._extractContent(item);
1608
+ notes.push(this._parseItem(item, notebookId, content));
1609
+ }
1610
+ return notes;
1611
+ }
1612
+ _isMindMap(content) {
1613
+ return content.includes('"children":') || content.includes('"nodes":');
1614
+ }
1615
+ _extractContent(item) {
1616
+ if (typeof item[1] === "string") return item[1];
1617
+ if (Array.isArray(item[1]) && typeof item[1][1] === "string") return item[1][1];
1618
+ return "";
1619
+ }
1620
+ _parseItem(item, _notebookId, content) {
1621
+ const inner = Array.isArray(item[1]) ? item[1] : null;
1622
+ const title = inner && typeof inner[4] === "string" && inner[4] ? inner[4] : null;
1623
+ const createdAt = Array.isArray(item[3]) && typeof item[3][0] === "number" ? new Date(item[3][0] * 1e3) : null;
1624
+ return { id: item[0], title, content, createdAt, updatedAt: null };
1625
+ }
1529
1626
  };
1530
1627
 
1531
1628
  // src/api/research.ts
@@ -1662,7 +1759,7 @@ var ResearchAPI = class {
1662
1759
  const webSources = sources.filter((s) => s.url && !reportSourceSet.has(s));
1663
1760
  if (!webSources.length && !reportSources.length) return [];
1664
1761
  const sourceArray = [
1665
- ...reportSources.map((s) => buildReportEntry(s.title, s.reportMarkdown)),
1762
+ ...reportSources.filter((s) => s.reportMarkdown).map((s) => buildReportEntry(s.title, s.reportMarkdown)),
1666
1763
  ...webSources.map((s) => buildWebEntry(s.url, s.title))
1667
1764
  ];
1668
1765
  const params = [null, [1], effectiveTaskId, notebookId, sourceArray];
@@ -2392,9 +2489,9 @@ var NotebookLMClient = class _NotebookLMClient {
2392
2489
  const rpc = new RPCCore(auth, opts.timeoutMs);
2393
2490
  this.notebooks = new NotebooksAPI(rpc);
2394
2491
  this.sources = new SourcesAPI(rpc, auth);
2395
- this.artifacts = new ArtifactsAPI(rpc, auth);
2396
- this.chat = new ChatAPI(rpc, auth);
2397
2492
  this.notes = new NotesAPI(rpc);
2493
+ this.artifacts = new ArtifactsAPI(rpc, auth, this.notes);
2494
+ this.chat = new ChatAPI(rpc, auth);
2398
2495
  this.research = new ResearchAPI(rpc);
2399
2496
  this.settings = new SettingsAPI(rpc);
2400
2497
  this.sharing = new SharingAPI(rpc);