notebooklm-sdk 0.1.8 → 0.3.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/README.md +85 -242
- package/dist/auth.cjs +4 -10
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.js +4 -10
- package/dist/auth.js.map +1 -1
- package/dist/bin.cjs +4 -10
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +4 -10
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +324 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -20
- package/dist/index.d.ts +85 -20
- package/dist/index.js +325 -81
- package/dist/index.js.map +1 -1
- package/package.json +11 -3
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ __export(enums_exports, {
|
|
|
21
21
|
ArtifactTypeCode: () => exports.ArtifactTypeCode,
|
|
22
22
|
AudioFormat: () => exports.AudioFormat,
|
|
23
23
|
AudioLength: () => exports.AudioLength,
|
|
24
|
+
ChatMode: () => exports.ChatMode,
|
|
24
25
|
ExportType: () => exports.ExportType,
|
|
25
26
|
InfographicDetail: () => exports.InfographicDetail,
|
|
26
27
|
InfographicOrientation: () => exports.InfographicOrientation,
|
|
@@ -38,6 +39,7 @@ __export(enums_exports, {
|
|
|
38
39
|
VideoStyle: () => exports.VideoStyle,
|
|
39
40
|
artifactStatusFromCode: () => artifactStatusFromCode,
|
|
40
41
|
artifactTypeFromCode: () => artifactTypeFromCode,
|
|
42
|
+
chatModeToParams: () => chatModeToParams,
|
|
41
43
|
sourceStatusFromCode: () => sourceStatusFromCode,
|
|
42
44
|
sourceTypeFromCode: () => sourceTypeFromCode
|
|
43
45
|
});
|
|
@@ -59,7 +61,10 @@ function artifactStatusFromCode(code) {
|
|
|
59
61
|
function sourceStatusFromCode(code) {
|
|
60
62
|
return SOURCE_STATUS_MAP[code] ?? "unknown";
|
|
61
63
|
}
|
|
62
|
-
|
|
64
|
+
function chatModeToParams(mode) {
|
|
65
|
+
return CHAT_MODE_PARAMS[mode];
|
|
66
|
+
}
|
|
67
|
+
exports.RPCMethod = void 0; exports.ArtifactTypeCode = void 0; var ArtifactStatusCode, SourceStatusCode; exports.AudioFormat = void 0; exports.AudioLength = void 0; exports.VideoFormat = void 0; exports.VideoStyle = void 0; exports.QuizQuantity = void 0; exports.QuizDifficulty = void 0; exports.InfographicOrientation = void 0; exports.InfographicDetail = void 0; exports.InfographicStyle = void 0; exports.SlideDeckFormat = void 0; exports.SlideDeckLength = void 0; exports.ExportType = void 0; var SOURCE_TYPE_MAP, ARTIFACT_TYPE_MAP, ARTIFACT_STATUS_MAP, SOURCE_STATUS_MAP; exports.ChatMode = void 0; var CHAT_MODE_PARAMS; exports.ShareAccess = void 0; exports.ShareViewLevel = void 0; exports.SharePermission = void 0;
|
|
63
68
|
var init_enums = __esm({
|
|
64
69
|
"src/types/enums.ts"() {
|
|
65
70
|
exports.RPCMethod = {
|
|
@@ -243,6 +248,22 @@ var init_enums = __esm({
|
|
|
243
248
|
3: "error",
|
|
244
249
|
5: "preparing"
|
|
245
250
|
};
|
|
251
|
+
exports.ChatMode = {
|
|
252
|
+
/** General purpose — balanced length and style. */
|
|
253
|
+
DEFAULT: "default",
|
|
254
|
+
/** Educational focus with longer, learning-oriented responses. */
|
|
255
|
+
LEARNING_GUIDE: "learning_guide",
|
|
256
|
+
/** Short, concise answers. */
|
|
257
|
+
CONCISE: "concise",
|
|
258
|
+
/** Verbose, detailed answers. */
|
|
259
|
+
DETAILED: "detailed"
|
|
260
|
+
};
|
|
261
|
+
CHAT_MODE_PARAMS = {
|
|
262
|
+
default: [1, 1],
|
|
263
|
+
learning_guide: [3, 4],
|
|
264
|
+
concise: [1, 5],
|
|
265
|
+
detailed: [1, 4]
|
|
266
|
+
};
|
|
246
267
|
exports.ShareAccess = {
|
|
247
268
|
/** Only explicitly shared users can access */
|
|
248
269
|
RESTRICTED: 0,
|
|
@@ -455,10 +476,8 @@ function loadCookiesFromFile(filePath) {
|
|
|
455
476
|
try {
|
|
456
477
|
raw = fs.readFileSync(filePath, "utf-8");
|
|
457
478
|
} catch {
|
|
458
|
-
throw new exports.AuthError(
|
|
459
|
-
|
|
460
|
-
Run: npx notebooklm-sdk login`
|
|
461
|
-
);
|
|
479
|
+
throw new exports.AuthError(`Session file not found: ${filePath}
|
|
480
|
+
Run: npx notebooklm-sdk login`);
|
|
462
481
|
}
|
|
463
482
|
return extractCookiesFromStorageState(JSON.parse(raw));
|
|
464
483
|
}
|
|
@@ -592,9 +611,7 @@ async function connect(opts = {}) {
|
|
|
592
611
|
} else if (envCookies) {
|
|
593
612
|
cookieMap = loadCookiesFromString(envCookies);
|
|
594
613
|
} else {
|
|
595
|
-
throw new exports.AuthError(
|
|
596
|
-
"No session found. Run: npx notebooklm-sdk login"
|
|
597
|
-
);
|
|
614
|
+
throw new exports.AuthError("No session found. Run: npx notebooklm-sdk login");
|
|
598
615
|
}
|
|
599
616
|
}
|
|
600
617
|
const { csrfToken, sessionId } = await fetchTokens(cookieMap);
|
|
@@ -729,26 +746,6 @@ function parseArtifact(data, notebookId) {
|
|
|
729
746
|
_raw: Array.isArray(data) ? data : []
|
|
730
747
|
};
|
|
731
748
|
}
|
|
732
|
-
function parseNote(data) {
|
|
733
|
-
const id = typeof data[0] === "string" ? data[0] : "";
|
|
734
|
-
const content = typeof data[1] === "string" ? data[1] : "";
|
|
735
|
-
const title = typeof data[2] === "string" ? data[2] : null;
|
|
736
|
-
let createdAt = null;
|
|
737
|
-
let updatedAt = null;
|
|
738
|
-
if (Array.isArray(data[3]) && typeof data[3][0] === "number") {
|
|
739
|
-
try {
|
|
740
|
-
createdAt = new Date(data[3][0] * 1e3);
|
|
741
|
-
} catch {
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
if (Array.isArray(data[4]) && typeof data[4][0] === "number") {
|
|
745
|
-
try {
|
|
746
|
-
updatedAt = new Date(data[4][0] * 1e3);
|
|
747
|
-
} catch {
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
return { id, title, content, createdAt, updatedAt };
|
|
751
|
-
}
|
|
752
749
|
|
|
753
750
|
// src/api/artifacts.ts
|
|
754
751
|
function tripleNest(ids) {
|
|
@@ -758,18 +755,13 @@ function doubleNest(ids) {
|
|
|
758
755
|
return ids.map((id) => [id]);
|
|
759
756
|
}
|
|
760
757
|
var ArtifactsAPI = class {
|
|
761
|
-
constructor(rpc, auth) {
|
|
758
|
+
constructor(rpc, auth, notes) {
|
|
762
759
|
this.rpc = rpc;
|
|
763
760
|
this.auth = auth;
|
|
761
|
+
this.notes = notes;
|
|
764
762
|
}
|
|
765
763
|
async list(notebookId) {
|
|
766
|
-
const
|
|
767
|
-
const result = await this.rpc.call(exports.RPCMethod.LIST_ARTIFACTS, params, {
|
|
768
|
-
sourcePath: `/notebook/${notebookId}`,
|
|
769
|
-
allowNull: true
|
|
770
|
-
});
|
|
771
|
-
if (!Array.isArray(result) || !result.length) return [];
|
|
772
|
-
const rawList = Array.isArray(result[0]) ? result[0] : result;
|
|
764
|
+
const rawList = await this._listRaw(notebookId);
|
|
773
765
|
const artifacts = [];
|
|
774
766
|
for (const item of rawList) {
|
|
775
767
|
if (Array.isArray(item)) {
|
|
@@ -781,6 +773,15 @@ var ArtifactsAPI = class {
|
|
|
781
773
|
}
|
|
782
774
|
return artifacts;
|
|
783
775
|
}
|
|
776
|
+
async _listRaw(notebookId) {
|
|
777
|
+
const params = [[2], notebookId, 'NOT artifact.status = "ARTIFACT_STATUS_SUGGESTED"'];
|
|
778
|
+
const result = await this.rpc.call(exports.RPCMethod.LIST_ARTIFACTS, params, {
|
|
779
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
780
|
+
allowNull: true
|
|
781
|
+
});
|
|
782
|
+
if (!Array.isArray(result) || !result.length) return [];
|
|
783
|
+
return Array.isArray(result[0]) ? result[0] : result;
|
|
784
|
+
}
|
|
784
785
|
async get(notebookId, artifactId) {
|
|
785
786
|
const artifacts = await this.list(notebookId);
|
|
786
787
|
return artifacts.find((a) => a.id === artifactId) ?? null;
|
|
@@ -960,6 +961,37 @@ var ArtifactsAPI = class {
|
|
|
960
961
|
];
|
|
961
962
|
return this._callGenerate(notebookId, params);
|
|
962
963
|
}
|
|
964
|
+
async createDataTable(notebookId, opts = {}) {
|
|
965
|
+
const language = opts.language ?? "en";
|
|
966
|
+
const sourceIds = opts.sourceIds ?? await this.rpc.getSourceIds(notebookId);
|
|
967
|
+
const triple = tripleNest(sourceIds);
|
|
968
|
+
const params = [
|
|
969
|
+
[2],
|
|
970
|
+
notebookId,
|
|
971
|
+
[
|
|
972
|
+
null,
|
|
973
|
+
null,
|
|
974
|
+
exports.ArtifactTypeCode.DATA_TABLE,
|
|
975
|
+
triple,
|
|
976
|
+
null,
|
|
977
|
+
null,
|
|
978
|
+
null,
|
|
979
|
+
null,
|
|
980
|
+
null,
|
|
981
|
+
null,
|
|
982
|
+
null,
|
|
983
|
+
null,
|
|
984
|
+
null,
|
|
985
|
+
null,
|
|
986
|
+
null,
|
|
987
|
+
null,
|
|
988
|
+
null,
|
|
989
|
+
null,
|
|
990
|
+
[null, [opts.instructions ?? null, language]]
|
|
991
|
+
]
|
|
992
|
+
];
|
|
993
|
+
return this._callGenerate(notebookId, params);
|
|
994
|
+
}
|
|
963
995
|
async createReport(notebookId, opts = {}) {
|
|
964
996
|
const format = opts.format ?? "briefing_doc";
|
|
965
997
|
const language = opts.language ?? "en";
|
|
@@ -1025,7 +1057,15 @@ ${opts.extraInstructions}` : cfg.prompt;
|
|
|
1025
1057
|
sourcePath: `/notebook/${notebookId}`,
|
|
1026
1058
|
allowNull: true
|
|
1027
1059
|
});
|
|
1028
|
-
|
|
1060
|
+
const mindMapJson = Array.isArray(result) && Array.isArray(result[0]) && typeof result[0][0] === "string" ? result[0][0] : null;
|
|
1061
|
+
if (!mindMapJson) throw new Error("Mind map generation returned no content");
|
|
1062
|
+
let title = "Mind Map";
|
|
1063
|
+
try {
|
|
1064
|
+
const parsed = JSON.parse(mindMapJson);
|
|
1065
|
+
if (typeof parsed["name"] === "string") title = parsed["name"];
|
|
1066
|
+
} catch {
|
|
1067
|
+
}
|
|
1068
|
+
return this.notes.create(notebookId, mindMapJson, title);
|
|
1029
1069
|
}
|
|
1030
1070
|
// ---------------------------------------------------------------------------
|
|
1031
1071
|
// Polling / download
|
|
@@ -1081,6 +1121,81 @@ ${opts.extraInstructions}` : cfg.prompt;
|
|
|
1081
1121
|
}
|
|
1082
1122
|
return null;
|
|
1083
1123
|
}
|
|
1124
|
+
/** Download a completed slide deck as PDF or PPTX. Returns a Buffer. */
|
|
1125
|
+
async downloadSlideDeck(notebookId, artifactId, format = "pdf") {
|
|
1126
|
+
const rawList = await this._listRaw(notebookId);
|
|
1127
|
+
const raw = rawList.find(
|
|
1128
|
+
(a) => a[0] === artifactId && a[2] === exports.ArtifactTypeCode.SLIDE_DECK
|
|
1129
|
+
);
|
|
1130
|
+
if (!raw) throw new exports.ArtifactNotReadyError("slide_deck", { artifactId });
|
|
1131
|
+
const metadata = raw[16];
|
|
1132
|
+
if (!Array.isArray(metadata)) throw new exports.ArtifactNotReadyError("slide_deck", { artifactId });
|
|
1133
|
+
const url = format === "pptx" ? metadata[4] : metadata[3];
|
|
1134
|
+
if (typeof url !== "string" || !url.startsWith("http")) {
|
|
1135
|
+
throw new exports.ArtifactNotReadyError("slide_deck", { artifactId, status: `no ${format} url` });
|
|
1136
|
+
}
|
|
1137
|
+
return this._fetchMediaWithCookies(url);
|
|
1138
|
+
}
|
|
1139
|
+
/** Download a completed infographic as PNG. Returns a Buffer. */
|
|
1140
|
+
async downloadInfographic(notebookId, artifactId) {
|
|
1141
|
+
const rawList = await this._listRaw(notebookId);
|
|
1142
|
+
const raw = rawList.find(
|
|
1143
|
+
(a) => a[0] === artifactId && a[2] === exports.ArtifactTypeCode.INFOGRAPHIC
|
|
1144
|
+
);
|
|
1145
|
+
if (!raw) throw new exports.ArtifactNotReadyError("infographic", { artifactId });
|
|
1146
|
+
let url = null;
|
|
1147
|
+
for (let i = raw.length - 1; i >= 0; i--) {
|
|
1148
|
+
const item = raw[i];
|
|
1149
|
+
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")) {
|
|
1150
|
+
url = item[2][0][1][0];
|
|
1151
|
+
break;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
if (!url) throw new exports.ArtifactNotReadyError("infographic", { artifactId });
|
|
1155
|
+
return this._fetchMediaWithCookies(url);
|
|
1156
|
+
}
|
|
1157
|
+
/** Get AI-suggested report formats based on notebook content. */
|
|
1158
|
+
async suggestReports(notebookId) {
|
|
1159
|
+
const params = [[2], notebookId];
|
|
1160
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_SUGGESTED_REPORTS, params, {
|
|
1161
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1162
|
+
allowNull: true,
|
|
1163
|
+
timeoutMs: 12e4
|
|
1164
|
+
});
|
|
1165
|
+
if (!Array.isArray(result) || !result.length) return [];
|
|
1166
|
+
const items = Array.isArray(result[0]) ? result[0] : result;
|
|
1167
|
+
const suggestions = [];
|
|
1168
|
+
for (const item of items) {
|
|
1169
|
+
if (Array.isArray(item) && item.length >= 5) {
|
|
1170
|
+
suggestions.push({
|
|
1171
|
+
title: typeof item[0] === "string" ? item[0] : "",
|
|
1172
|
+
description: typeof item[1] === "string" ? item[1] : "",
|
|
1173
|
+
prompt: typeof item[4] === "string" ? item[4] : "",
|
|
1174
|
+
audienceLevel: typeof item[5] === "number" ? item[5] : 2
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return suggestions;
|
|
1179
|
+
}
|
|
1180
|
+
/** Revise an individual slide in a completed slide deck using a prompt. */
|
|
1181
|
+
async reviseSlide(notebookId, artifactId, slideIndex, prompt) {
|
|
1182
|
+
if (slideIndex < 0) throw new Error("slideIndex must be >= 0");
|
|
1183
|
+
const params = [[2], artifactId, [[[slideIndex, prompt]]]];
|
|
1184
|
+
const result = await this.rpc.call(exports.RPCMethod.REVISE_SLIDE, params, {
|
|
1185
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1186
|
+
allowNull: true
|
|
1187
|
+
});
|
|
1188
|
+
return this._parseGenerationResult(result);
|
|
1189
|
+
}
|
|
1190
|
+
/** Get parsed headers and rows from a completed data table artifact. */
|
|
1191
|
+
async getDataTableContent(notebookId, artifactId) {
|
|
1192
|
+
const artifacts = await this._listRaw(notebookId);
|
|
1193
|
+
const raw = artifacts.find(
|
|
1194
|
+
(a) => Array.isArray(a) && a[0] === artifactId && a[2] === exports.ArtifactTypeCode.DATA_TABLE
|
|
1195
|
+
);
|
|
1196
|
+
if (!raw || !Array.isArray(raw) || !Array.isArray(raw[18])) return null;
|
|
1197
|
+
return parseDataTable(raw[18]);
|
|
1198
|
+
}
|
|
1084
1199
|
// ---------------------------------------------------------------------------
|
|
1085
1200
|
// Internal
|
|
1086
1201
|
// ---------------------------------------------------------------------------
|
|
@@ -1137,6 +1252,34 @@ ${opts.extraInstructions}` : cfg.prompt;
|
|
|
1137
1252
|
return { artifactId: null, status: "failed" };
|
|
1138
1253
|
}
|
|
1139
1254
|
};
|
|
1255
|
+
function extractCellText(cell) {
|
|
1256
|
+
if (typeof cell === "string") return cell;
|
|
1257
|
+
if (typeof cell === "number") return "";
|
|
1258
|
+
if (Array.isArray(cell)) return cell.map(extractCellText).join("");
|
|
1259
|
+
return "";
|
|
1260
|
+
}
|
|
1261
|
+
function parseDataTable(rawData) {
|
|
1262
|
+
try {
|
|
1263
|
+
const nav = rawData;
|
|
1264
|
+
const rowsArray = nav[0][0][0][0][4][2];
|
|
1265
|
+
if (!rowsArray?.length) throw new Error("Empty data table");
|
|
1266
|
+
const headers = [];
|
|
1267
|
+
const rows = [];
|
|
1268
|
+
for (let i = 0; i < rowsArray.length; i++) {
|
|
1269
|
+
const rowSection = rowsArray[i];
|
|
1270
|
+
if (!Array.isArray(rowSection) || rowSection.length < 3) continue;
|
|
1271
|
+
const cellArray = rowSection[2];
|
|
1272
|
+
if (!Array.isArray(cellArray)) continue;
|
|
1273
|
+
const values = cellArray.map(extractCellText);
|
|
1274
|
+
if (i === 0) headers.push(...values);
|
|
1275
|
+
else rows.push(values);
|
|
1276
|
+
}
|
|
1277
|
+
if (!headers.length) throw new Error("No headers found");
|
|
1278
|
+
return { headers, rows };
|
|
1279
|
+
} catch (e) {
|
|
1280
|
+
throw new Error(`Failed to parse data table: ${e}`);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1140
1283
|
function sleep(ms) {
|
|
1141
1284
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1142
1285
|
}
|
|
@@ -1267,6 +1410,19 @@ var ChatAPI = class {
|
|
|
1267
1410
|
}
|
|
1268
1411
|
return null;
|
|
1269
1412
|
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Set the chat mode for a notebook. Persists on the server — affects all
|
|
1415
|
+
* subsequent `ask()` calls until changed.
|
|
1416
|
+
*/
|
|
1417
|
+
async setMode(notebookId, mode) {
|
|
1418
|
+
const [goal, length] = chatModeToParams(mode);
|
|
1419
|
+
const chatSettings = [[goal], [length]];
|
|
1420
|
+
const params = [notebookId, [[null, null, null, null, null, null, null, chatSettings]]];
|
|
1421
|
+
await this.rpc.call(exports.RPCMethod.RENAME_NOTEBOOK, params, {
|
|
1422
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1423
|
+
allowNull: true
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1270
1426
|
clearCache(conversationId) {
|
|
1271
1427
|
if (conversationId) {
|
|
1272
1428
|
this.conversationCache.delete(conversationId);
|
|
@@ -1437,6 +1593,9 @@ var NotebooksAPI = class {
|
|
|
1437
1593
|
}
|
|
1438
1594
|
return "";
|
|
1439
1595
|
}
|
|
1596
|
+
async removeFromRecent(notebookId) {
|
|
1597
|
+
await this.rpc.call(exports.RPCMethod.REMOVE_RECENTLY_VIEWED, [notebookId], { allowNull: true });
|
|
1598
|
+
}
|
|
1440
1599
|
async getDescription(notebookId) {
|
|
1441
1600
|
const params = [notebookId, [2]];
|
|
1442
1601
|
const result = await this.rpc.call(exports.RPCMethod.SUMMARIZE, params, {
|
|
@@ -1473,61 +1632,69 @@ var NotesAPI = class {
|
|
|
1473
1632
|
this.rpc = rpc;
|
|
1474
1633
|
}
|
|
1475
1634
|
async list(notebookId) {
|
|
1476
|
-
const
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
const
|
|
1481
|
-
|
|
1482
|
-
if (!Array.isArray(result)) return { notes, mindMaps };
|
|
1483
|
-
try {
|
|
1484
|
-
const notesData = result[0];
|
|
1485
|
-
if (Array.isArray(notesData)) {
|
|
1486
|
-
for (const n of notesData) {
|
|
1487
|
-
if (Array.isArray(n)) notes.push(parseNote(n));
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
const mapsData = result[1];
|
|
1491
|
-
if (Array.isArray(mapsData)) {
|
|
1492
|
-
for (const m of mapsData) {
|
|
1493
|
-
if (Array.isArray(m)) {
|
|
1494
|
-
mindMaps.push({
|
|
1495
|
-
id: typeof m[0] === "string" ? m[0] : "",
|
|
1496
|
-
title: typeof m[2] === "string" ? m[2] : null,
|
|
1497
|
-
content: typeof m[1] === "string" ? m[1] : "",
|
|
1498
|
-
createdAt: Array.isArray(m[3]) && typeof m[3][0] === "number" ? new Date(m[3][0] * 1e3) : null
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1503
|
-
} catch {
|
|
1504
|
-
}
|
|
1505
|
-
return { notes, mindMaps };
|
|
1635
|
+
const all = await this._fetchAll(notebookId);
|
|
1636
|
+
return all.filter((n) => !this._isMindMap(n.content));
|
|
1637
|
+
}
|
|
1638
|
+
async listMindMaps(notebookId) {
|
|
1639
|
+
const all = await this._fetchAll(notebookId);
|
|
1640
|
+
return all.filter((n) => this._isMindMap(n.content));
|
|
1506
1641
|
}
|
|
1507
1642
|
async create(notebookId, content, title) {
|
|
1508
|
-
const
|
|
1509
|
-
const result = await this.rpc.call(exports.RPCMethod.CREATE_NOTE,
|
|
1510
|
-
sourcePath: `/notebook/${notebookId}
|
|
1643
|
+
const createParams = [notebookId, "", [1], null, "New Note"];
|
|
1644
|
+
const result = await this.rpc.call(exports.RPCMethod.CREATE_NOTE, createParams, {
|
|
1645
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1646
|
+
allowNull: true
|
|
1511
1647
|
});
|
|
1512
|
-
|
|
1513
|
-
throw new Error("
|
|
1648
|
+
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;
|
|
1649
|
+
if (!noteId) throw new Error("CREATE_NOTE did not return a note ID");
|
|
1650
|
+
await this.update(notebookId, noteId, content, title ?? "New Note");
|
|
1651
|
+
return { id: noteId, title: title ?? null, content, createdAt: null, updatedAt: /* @__PURE__ */ new Date() };
|
|
1514
1652
|
}
|
|
1515
1653
|
async update(notebookId, noteId, content, title) {
|
|
1516
|
-
const params = [notebookId, noteId, content, title ??
|
|
1517
|
-
|
|
1518
|
-
sourcePath: `/notebook/${notebookId}
|
|
1654
|
+
const params = [notebookId, noteId, [[[content, title ?? "New Note", [], 0]]]];
|
|
1655
|
+
await this.rpc.call(exports.RPCMethod.UPDATE_NOTE, params, {
|
|
1656
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1657
|
+
allowNull: true
|
|
1519
1658
|
});
|
|
1520
|
-
if (Array.isArray(result)) return parseNote(result);
|
|
1521
1659
|
return { id: noteId, title: title ?? null, content, createdAt: null, updatedAt: /* @__PURE__ */ new Date() };
|
|
1522
1660
|
}
|
|
1523
1661
|
async delete(notebookId, noteId) {
|
|
1524
|
-
const params = [notebookId,
|
|
1662
|
+
const params = [notebookId, null, [noteId]];
|
|
1525
1663
|
await this.rpc.call(exports.RPCMethod.DELETE_NOTE, params, {
|
|
1526
1664
|
sourcePath: `/notebook/${notebookId}`,
|
|
1527
1665
|
allowNull: true
|
|
1528
1666
|
});
|
|
1529
1667
|
return true;
|
|
1530
1668
|
}
|
|
1669
|
+
async _fetchAll(notebookId) {
|
|
1670
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_NOTES_AND_MIND_MAPS, [notebookId], {
|
|
1671
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1672
|
+
allowNull: true
|
|
1673
|
+
});
|
|
1674
|
+
if (!Array.isArray(result) || !Array.isArray(result[0])) return [];
|
|
1675
|
+
const notes = [];
|
|
1676
|
+
for (const item of result[0]) {
|
|
1677
|
+
if (!Array.isArray(item) || typeof item[0] !== "string") continue;
|
|
1678
|
+
if (item[1] === null && item[2] === 2) continue;
|
|
1679
|
+
const content = this._extractContent(item);
|
|
1680
|
+
notes.push(this._parseItem(item, notebookId, content));
|
|
1681
|
+
}
|
|
1682
|
+
return notes;
|
|
1683
|
+
}
|
|
1684
|
+
_isMindMap(content) {
|
|
1685
|
+
return content.includes('"children":') || content.includes('"nodes":');
|
|
1686
|
+
}
|
|
1687
|
+
_extractContent(item) {
|
|
1688
|
+
if (typeof item[1] === "string") return item[1];
|
|
1689
|
+
if (Array.isArray(item[1]) && typeof item[1][1] === "string") return item[1][1];
|
|
1690
|
+
return "";
|
|
1691
|
+
}
|
|
1692
|
+
_parseItem(item, _notebookId, content) {
|
|
1693
|
+
const inner = Array.isArray(item[1]) ? item[1] : null;
|
|
1694
|
+
const title = inner && typeof inner[4] === "string" && inner[4] ? inner[4] : null;
|
|
1695
|
+
const createdAt = Array.isArray(item[3]) && typeof item[3][0] === "number" ? new Date(item[3][0] * 1e3) : null;
|
|
1696
|
+
return { id: item[0], title, content, createdAt, updatedAt: null };
|
|
1697
|
+
}
|
|
1531
1698
|
};
|
|
1532
1699
|
|
|
1533
1700
|
// src/api/research.ts
|
|
@@ -1664,7 +1831,7 @@ var ResearchAPI = class {
|
|
|
1664
1831
|
const webSources = sources.filter((s) => s.url && !reportSourceSet.has(s));
|
|
1665
1832
|
if (!webSources.length && !reportSources.length) return [];
|
|
1666
1833
|
const sourceArray = [
|
|
1667
|
-
...reportSources.map((s) => buildReportEntry(s.title, s.reportMarkdown)),
|
|
1834
|
+
...reportSources.filter((s) => s.reportMarkdown).map((s) => buildReportEntry(s.title, s.reportMarkdown)),
|
|
1668
1835
|
...webSources.map((s) => buildWebEntry(s.url, s.title))
|
|
1669
1836
|
];
|
|
1670
1837
|
const params = [null, [1], effectiveTaskId, notebookId, sourceArray];
|
|
@@ -2036,6 +2203,74 @@ var SourcesAPI = class {
|
|
|
2036
2203
|
const uploadResult = await uploadResp.text();
|
|
2037
2204
|
return uploadResult.trim();
|
|
2038
2205
|
}
|
|
2206
|
+
/** Get the AI-generated Source Guide (summary + keywords) for a source. */
|
|
2207
|
+
async getGuide(notebookId, sourceId) {
|
|
2208
|
+
const params = [[[[sourceId]]]];
|
|
2209
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_SOURCE_GUIDE, params, {
|
|
2210
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
2211
|
+
allowNull: true,
|
|
2212
|
+
timeoutMs: 12e4
|
|
2213
|
+
});
|
|
2214
|
+
let summary = "";
|
|
2215
|
+
let keywords = [];
|
|
2216
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
2217
|
+
const outer = result[0];
|
|
2218
|
+
if (Array.isArray(outer) && outer.length > 0) {
|
|
2219
|
+
const inner = outer[0];
|
|
2220
|
+
if (Array.isArray(inner)) {
|
|
2221
|
+
if (inner.length > 1 && Array.isArray(inner[1]) && typeof inner[1][0] === "string") {
|
|
2222
|
+
summary = inner[1][0];
|
|
2223
|
+
}
|
|
2224
|
+
if (inner.length > 2 && Array.isArray(inner[2]) && Array.isArray(inner[2][0])) {
|
|
2225
|
+
keywords = inner[2][0].filter((k) => typeof k === "string");
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
return { summary, keywords };
|
|
2231
|
+
}
|
|
2232
|
+
/** Get the full indexed text content of a source. */
|
|
2233
|
+
async getFulltext(notebookId, sourceId) {
|
|
2234
|
+
const params = [[sourceId], [2], [2]];
|
|
2235
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_SOURCE, params, {
|
|
2236
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
2237
|
+
allowNull: true
|
|
2238
|
+
});
|
|
2239
|
+
if (!Array.isArray(result) || !result.length) {
|
|
2240
|
+
throw new Error(`Source ${sourceId} not found in notebook ${notebookId}`);
|
|
2241
|
+
}
|
|
2242
|
+
let title = "";
|
|
2243
|
+
let url = null;
|
|
2244
|
+
if (Array.isArray(result[0]) && result[0].length > 1) {
|
|
2245
|
+
title = typeof result[0][1] === "string" ? result[0][1] : "";
|
|
2246
|
+
const meta = result[0][2];
|
|
2247
|
+
if (Array.isArray(meta) && meta.length > 7 && Array.isArray(meta[7]) && typeof meta[7][0] === "string") {
|
|
2248
|
+
url = meta[7][0];
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
let content = "";
|
|
2252
|
+
if (Array.isArray(result[3]) && result[3].length > 0) {
|
|
2253
|
+
const texts = extractAllText(result[3][0]);
|
|
2254
|
+
content = texts.join("\n");
|
|
2255
|
+
}
|
|
2256
|
+
return { sourceId, title, content, url, charCount: content.length };
|
|
2257
|
+
}
|
|
2258
|
+
/** Check if a source has newer content available. Returns true if fresh, false if stale. */
|
|
2259
|
+
async checkFreshness(notebookId, sourceId) {
|
|
2260
|
+
const params = [null, [sourceId], [2]];
|
|
2261
|
+
const result = await this.rpc.call(exports.RPCMethod.CHECK_SOURCE_FRESHNESS, params, {
|
|
2262
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
2263
|
+
allowNull: true
|
|
2264
|
+
});
|
|
2265
|
+
if (result === true) return true;
|
|
2266
|
+
if (result === false) return false;
|
|
2267
|
+
if (Array.isArray(result)) {
|
|
2268
|
+
if (result.length === 0) return true;
|
|
2269
|
+
const first = result[0];
|
|
2270
|
+
if (Array.isArray(first) && first.length > 1 && first[1] === true) return true;
|
|
2271
|
+
}
|
|
2272
|
+
return false;
|
|
2273
|
+
}
|
|
2039
2274
|
async delete(notebookId, sourceId) {
|
|
2040
2275
|
const params = [notebookId, [sourceId], [2]];
|
|
2041
2276
|
await this.rpc.call(exports.RPCMethod.DELETE_SOURCE, params, {
|
|
@@ -2090,6 +2325,15 @@ function extractSourceId(result) {
|
|
|
2090
2325
|
console.log("extractSourceId debug info: could not parse:", JSON.stringify(result, null, 2));
|
|
2091
2326
|
throw new Error("Could not extract source ID from API response");
|
|
2092
2327
|
}
|
|
2328
|
+
function extractAllText(data, maxDepth = 100) {
|
|
2329
|
+
if (maxDepth <= 0) return [];
|
|
2330
|
+
const texts = [];
|
|
2331
|
+
for (const item of data) {
|
|
2332
|
+
if (typeof item === "string" && item.length > 0) texts.push(item);
|
|
2333
|
+
else if (Array.isArray(item)) texts.push(...extractAllText(item, maxDepth - 1));
|
|
2334
|
+
}
|
|
2335
|
+
return texts;
|
|
2336
|
+
}
|
|
2093
2337
|
function sleep2(ms) {
|
|
2094
2338
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2095
2339
|
}
|
|
@@ -2394,9 +2638,9 @@ var NotebookLMClient = class _NotebookLMClient {
|
|
|
2394
2638
|
const rpc = new RPCCore(auth, opts.timeoutMs);
|
|
2395
2639
|
this.notebooks = new NotebooksAPI(rpc);
|
|
2396
2640
|
this.sources = new SourcesAPI(rpc, auth);
|
|
2397
|
-
this.artifacts = new ArtifactsAPI(rpc, auth);
|
|
2398
|
-
this.chat = new ChatAPI(rpc, auth);
|
|
2399
2641
|
this.notes = new NotesAPI(rpc);
|
|
2642
|
+
this.artifacts = new ArtifactsAPI(rpc, auth, this.notes);
|
|
2643
|
+
this.chat = new ChatAPI(rpc, auth);
|
|
2400
2644
|
this.research = new ResearchAPI(rpc);
|
|
2401
2645
|
this.settings = new SettingsAPI(rpc);
|
|
2402
2646
|
this.sharing = new SharingAPI(rpc);
|