notebooklm-sdk 0.1.2 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -134
- package/dist/auth-DTugbaf3.d.cts +55 -0
- package/dist/auth-DTugbaf3.d.ts +55 -0
- package/dist/auth.cjs +231 -0
- package/dist/auth.cjs.map +1 -0
- package/dist/auth.d.cts +35 -0
- package/dist/auth.d.ts +35 -0
- package/dist/auth.js +221 -0
- package/dist/auth.js.map +1 -0
- package/dist/index.cjs +1344 -1304
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -74
- package/dist/index.d.ts +50 -74
- package/dist/index.js +1344 -1304
- package/dist/index.js.map +1 -1
- package/package.json +23 -5
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,257 @@ var __export = (target, all) => {
|
|
|
12
12
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
// src/types/enums.ts
|
|
16
|
+
var enums_exports = {};
|
|
17
|
+
__export(enums_exports, {
|
|
18
|
+
ArtifactStatusCode: () => ArtifactStatusCode,
|
|
19
|
+
ArtifactTypeCode: () => exports.ArtifactTypeCode,
|
|
20
|
+
AudioFormat: () => exports.AudioFormat,
|
|
21
|
+
AudioLength: () => exports.AudioLength,
|
|
22
|
+
ExportType: () => exports.ExportType,
|
|
23
|
+
InfographicDetail: () => exports.InfographicDetail,
|
|
24
|
+
InfographicOrientation: () => exports.InfographicOrientation,
|
|
25
|
+
InfographicStyle: () => exports.InfographicStyle,
|
|
26
|
+
QuizDifficulty: () => exports.QuizDifficulty,
|
|
27
|
+
QuizQuantity: () => exports.QuizQuantity,
|
|
28
|
+
RPCMethod: () => exports.RPCMethod,
|
|
29
|
+
ShareAccess: () => exports.ShareAccess,
|
|
30
|
+
SharePermission: () => exports.SharePermission,
|
|
31
|
+
ShareViewLevel: () => exports.ShareViewLevel,
|
|
32
|
+
SlideDeckFormat: () => exports.SlideDeckFormat,
|
|
33
|
+
SlideDeckLength: () => exports.SlideDeckLength,
|
|
34
|
+
SourceStatusCode: () => SourceStatusCode,
|
|
35
|
+
VideoFormat: () => exports.VideoFormat,
|
|
36
|
+
VideoStyle: () => exports.VideoStyle,
|
|
37
|
+
artifactStatusFromCode: () => artifactStatusFromCode,
|
|
38
|
+
artifactTypeFromCode: () => artifactTypeFromCode,
|
|
39
|
+
sourceStatusFromCode: () => sourceStatusFromCode,
|
|
40
|
+
sourceTypeFromCode: () => sourceTypeFromCode
|
|
41
|
+
});
|
|
42
|
+
function sourceTypeFromCode(code) {
|
|
43
|
+
if (code == null) return "unknown";
|
|
44
|
+
return SOURCE_TYPE_MAP[code] ?? "unknown";
|
|
45
|
+
}
|
|
46
|
+
function artifactTypeFromCode(typeCode, variant) {
|
|
47
|
+
if (typeCode === 4) {
|
|
48
|
+
if (variant === 1) return "flashcards";
|
|
49
|
+
if (variant === 2) return "quiz";
|
|
50
|
+
return "unknown";
|
|
51
|
+
}
|
|
52
|
+
return ARTIFACT_TYPE_MAP[typeCode] ?? "unknown";
|
|
53
|
+
}
|
|
54
|
+
function artifactStatusFromCode(code) {
|
|
55
|
+
return ARTIFACT_STATUS_MAP[code] ?? "unknown";
|
|
56
|
+
}
|
|
57
|
+
function sourceStatusFromCode(code) {
|
|
58
|
+
return SOURCE_STATUS_MAP[code] ?? "unknown";
|
|
59
|
+
}
|
|
60
|
+
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.ShareAccess = void 0; exports.ShareViewLevel = void 0; exports.SharePermission = void 0;
|
|
61
|
+
var init_enums = __esm({
|
|
62
|
+
"src/types/enums.ts"() {
|
|
63
|
+
exports.RPCMethod = {
|
|
64
|
+
// Notebook
|
|
65
|
+
LIST_NOTEBOOKS: "wXbhsf",
|
|
66
|
+
CREATE_NOTEBOOK: "CCqFvf",
|
|
67
|
+
GET_NOTEBOOK: "rLM1Ne",
|
|
68
|
+
RENAME_NOTEBOOK: "s0tc2d",
|
|
69
|
+
DELETE_NOTEBOOK: "WWINqb",
|
|
70
|
+
// Sources
|
|
71
|
+
ADD_SOURCE: "izAoDd",
|
|
72
|
+
ADD_SOURCE_FILE: "o4cbdc",
|
|
73
|
+
DELETE_SOURCE: "tGMBJ",
|
|
74
|
+
GET_SOURCE: "hizoJc",
|
|
75
|
+
REFRESH_SOURCE: "FLmJqe",
|
|
76
|
+
CHECK_SOURCE_FRESHNESS: "yR9Yof",
|
|
77
|
+
UPDATE_SOURCE: "b7Wfje",
|
|
78
|
+
// Summary
|
|
79
|
+
SUMMARIZE: "VfAZjd",
|
|
80
|
+
GET_SOURCE_GUIDE: "tr032e",
|
|
81
|
+
GET_SUGGESTED_REPORTS: "ciyUvf",
|
|
82
|
+
// Artifacts
|
|
83
|
+
CREATE_ARTIFACT: "R7cb6c",
|
|
84
|
+
LIST_ARTIFACTS: "gArtLc",
|
|
85
|
+
DELETE_ARTIFACT: "V5N4be",
|
|
86
|
+
RENAME_ARTIFACT: "rc3d8d",
|
|
87
|
+
EXPORT_ARTIFACT: "Krh3pd",
|
|
88
|
+
SHARE_ARTIFACT: "RGP97b",
|
|
89
|
+
GET_INTERACTIVE_HTML: "v9rmvd",
|
|
90
|
+
REVISE_SLIDE: "KmcKPe",
|
|
91
|
+
// Research
|
|
92
|
+
START_FAST_RESEARCH: "Ljjv0c",
|
|
93
|
+
START_DEEP_RESEARCH: "QA9ei",
|
|
94
|
+
POLL_RESEARCH: "e3bVqc",
|
|
95
|
+
IMPORT_RESEARCH: "LBwxtb",
|
|
96
|
+
// Notes / Mind Maps
|
|
97
|
+
GENERATE_MIND_MAP: "yyryJe",
|
|
98
|
+
CREATE_NOTE: "CYK0Xb",
|
|
99
|
+
GET_NOTES_AND_MIND_MAPS: "cFji9",
|
|
100
|
+
UPDATE_NOTE: "cYAfTb",
|
|
101
|
+
DELETE_NOTE: "AH0mwd",
|
|
102
|
+
// Conversation
|
|
103
|
+
GET_LAST_CONVERSATION_ID: "hPTbtc",
|
|
104
|
+
GET_CONVERSATION_TURNS: "khqZz",
|
|
105
|
+
// Sharing
|
|
106
|
+
SHARE_NOTEBOOK: "QDyure",
|
|
107
|
+
GET_SHARE_STATUS: "JFMDGd",
|
|
108
|
+
// Misc
|
|
109
|
+
REMOVE_RECENTLY_VIEWED: "fejl7e",
|
|
110
|
+
GET_USER_SETTINGS: "ZwVcOc",
|
|
111
|
+
SET_USER_SETTINGS: "hT54vc"
|
|
112
|
+
};
|
|
113
|
+
exports.ArtifactTypeCode = {
|
|
114
|
+
AUDIO: 1,
|
|
115
|
+
REPORT: 2,
|
|
116
|
+
VIDEO: 3,
|
|
117
|
+
QUIZ: 4,
|
|
118
|
+
MIND_MAP: 5,
|
|
119
|
+
INFOGRAPHIC: 7,
|
|
120
|
+
SLIDE_DECK: 8,
|
|
121
|
+
DATA_TABLE: 9
|
|
122
|
+
};
|
|
123
|
+
ArtifactStatusCode = {
|
|
124
|
+
PROCESSING: 1,
|
|
125
|
+
PENDING: 2,
|
|
126
|
+
COMPLETED: 3,
|
|
127
|
+
FAILED: 4
|
|
128
|
+
};
|
|
129
|
+
SourceStatusCode = {
|
|
130
|
+
PROCESSING: 1,
|
|
131
|
+
READY: 2,
|
|
132
|
+
ERROR: 3,
|
|
133
|
+
PREPARING: 5
|
|
134
|
+
};
|
|
135
|
+
exports.AudioFormat = {
|
|
136
|
+
DEEP_DIVE: 1,
|
|
137
|
+
BRIEF: 2,
|
|
138
|
+
CRITIQUE: 3,
|
|
139
|
+
DEBATE: 4
|
|
140
|
+
};
|
|
141
|
+
exports.AudioLength = {
|
|
142
|
+
SHORT: 1,
|
|
143
|
+
DEFAULT: 2,
|
|
144
|
+
LONG: 3
|
|
145
|
+
};
|
|
146
|
+
exports.VideoFormat = {
|
|
147
|
+
EXPLAINER: 1,
|
|
148
|
+
BRIEF: 2,
|
|
149
|
+
CINEMATIC: 3
|
|
150
|
+
};
|
|
151
|
+
exports.VideoStyle = {
|
|
152
|
+
AUTO_SELECT: 1,
|
|
153
|
+
CUSTOM: 2,
|
|
154
|
+
CLASSIC: 3,
|
|
155
|
+
WHITEBOARD: 4,
|
|
156
|
+
KAWAII: 5,
|
|
157
|
+
ANIME: 6,
|
|
158
|
+
WATERCOLOR: 7,
|
|
159
|
+
RETRO_PRINT: 8,
|
|
160
|
+
HERITAGE: 9,
|
|
161
|
+
PAPER_CRAFT: 10
|
|
162
|
+
};
|
|
163
|
+
exports.QuizQuantity = {
|
|
164
|
+
FEWER: 1,
|
|
165
|
+
STANDARD: 2,
|
|
166
|
+
MORE: 2
|
|
167
|
+
// API limitation: same as STANDARD
|
|
168
|
+
};
|
|
169
|
+
exports.QuizDifficulty = {
|
|
170
|
+
EASY: 1,
|
|
171
|
+
MEDIUM: 2,
|
|
172
|
+
HARD: 3
|
|
173
|
+
};
|
|
174
|
+
exports.InfographicOrientation = {
|
|
175
|
+
LANDSCAPE: 1,
|
|
176
|
+
PORTRAIT: 2,
|
|
177
|
+
SQUARE: 3
|
|
178
|
+
};
|
|
179
|
+
exports.InfographicDetail = {
|
|
180
|
+
CONCISE: 1,
|
|
181
|
+
STANDARD: 2,
|
|
182
|
+
DETAILED: 3
|
|
183
|
+
};
|
|
184
|
+
exports.InfographicStyle = {
|
|
185
|
+
AUTO_SELECT: 1,
|
|
186
|
+
SKETCH_NOTE: 2,
|
|
187
|
+
PROFESSIONAL: 3,
|
|
188
|
+
BENTO_GRID: 4,
|
|
189
|
+
EDITORIAL: 5,
|
|
190
|
+
INSTRUCTIONAL: 6,
|
|
191
|
+
BRICKS: 7,
|
|
192
|
+
CLAY: 8,
|
|
193
|
+
ANIME: 9,
|
|
194
|
+
KAWAII: 10,
|
|
195
|
+
SCIENTIFIC: 11
|
|
196
|
+
};
|
|
197
|
+
exports.SlideDeckFormat = {
|
|
198
|
+
DETAILED_DECK: 1,
|
|
199
|
+
PRESENTER_SLIDES: 2
|
|
200
|
+
};
|
|
201
|
+
exports.SlideDeckLength = {
|
|
202
|
+
DEFAULT: 1,
|
|
203
|
+
SHORT: 2
|
|
204
|
+
};
|
|
205
|
+
exports.ExportType = {
|
|
206
|
+
DOCS: 1,
|
|
207
|
+
SHEETS: 2
|
|
208
|
+
};
|
|
209
|
+
SOURCE_TYPE_MAP = {
|
|
210
|
+
1: "google_docs",
|
|
211
|
+
2: "google_slides",
|
|
212
|
+
3: "pdf",
|
|
213
|
+
4: "pasted_text",
|
|
214
|
+
5: "web_page",
|
|
215
|
+
8: "markdown",
|
|
216
|
+
9: "youtube",
|
|
217
|
+
10: "media",
|
|
218
|
+
11: "docx",
|
|
219
|
+
13: "image",
|
|
220
|
+
14: "google_spreadsheet",
|
|
221
|
+
16: "csv"
|
|
222
|
+
};
|
|
223
|
+
ARTIFACT_TYPE_MAP = {
|
|
224
|
+
1: "audio",
|
|
225
|
+
2: "report",
|
|
226
|
+
3: "video",
|
|
227
|
+
5: "mind_map",
|
|
228
|
+
7: "infographic",
|
|
229
|
+
8: "slide_deck",
|
|
230
|
+
9: "data_table"
|
|
231
|
+
};
|
|
232
|
+
ARTIFACT_STATUS_MAP = {
|
|
233
|
+
1: "in_progress",
|
|
234
|
+
2: "pending",
|
|
235
|
+
3: "completed",
|
|
236
|
+
4: "failed"
|
|
237
|
+
};
|
|
238
|
+
SOURCE_STATUS_MAP = {
|
|
239
|
+
1: "processing",
|
|
240
|
+
2: "ready",
|
|
241
|
+
3: "error",
|
|
242
|
+
5: "preparing"
|
|
243
|
+
};
|
|
244
|
+
exports.ShareAccess = {
|
|
245
|
+
/** Only explicitly shared users can access */
|
|
246
|
+
RESTRICTED: 0,
|
|
247
|
+
/** Anyone with the link can access */
|
|
248
|
+
ANYONE_WITH_LINK: 1
|
|
249
|
+
};
|
|
250
|
+
exports.ShareViewLevel = {
|
|
251
|
+
/** Chat + sources + notes */
|
|
252
|
+
FULL_NOTEBOOK: 0,
|
|
253
|
+
/** Chat interface only */
|
|
254
|
+
CHAT_ONLY: 1
|
|
255
|
+
};
|
|
256
|
+
exports.SharePermission = {
|
|
257
|
+
OWNER: 1,
|
|
258
|
+
EDITOR: 2,
|
|
259
|
+
VIEWER: 3,
|
|
260
|
+
/** Internal: remove user from share list */
|
|
261
|
+
_REMOVE: 4
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
15
266
|
// src/types/errors.ts
|
|
16
267
|
exports.NotebookLMError = void 0; exports.NetworkError = void 0; exports.RPCTimeoutError = void 0; exports.RPCError = void 0; exports.AuthError = void 0; exports.RateLimitError = void 0; exports.ServerError = void 0; exports.ClientError = void 0; exports.NotebookError = void 0; exports.NotebookNotFoundError = void 0; exports.SourceError = void 0; exports.SourceNotFoundError = void 0; exports.SourceAddError = void 0; exports.SourceProcessingError = void 0; exports.SourceTimeoutError = void 0; exports.ArtifactError = void 0; exports.ArtifactNotFoundError = void 0; exports.ArtifactNotReadyError = void 0; exports.ArtifactParseError = void 0; exports.ArtifactDownloadError = void 0; exports.ChatError = void 0;
|
|
17
268
|
var init_errors = __esm({
|
|
@@ -349,543 +600,9 @@ var init_auth = __esm({
|
|
|
349
600
|
}
|
|
350
601
|
});
|
|
351
602
|
|
|
352
|
-
// src/
|
|
353
|
-
var enums_exports = {};
|
|
354
|
-
__export(enums_exports, {
|
|
355
|
-
ArtifactStatusCode: () => ArtifactStatusCode,
|
|
356
|
-
ArtifactTypeCode: () => exports.ArtifactTypeCode,
|
|
357
|
-
AudioFormat: () => exports.AudioFormat,
|
|
358
|
-
AudioLength: () => exports.AudioLength,
|
|
359
|
-
ExportType: () => exports.ExportType,
|
|
360
|
-
InfographicDetail: () => exports.InfographicDetail,
|
|
361
|
-
InfographicOrientation: () => exports.InfographicOrientation,
|
|
362
|
-
InfographicStyle: () => exports.InfographicStyle,
|
|
363
|
-
QuizDifficulty: () => exports.QuizDifficulty,
|
|
364
|
-
QuizQuantity: () => exports.QuizQuantity,
|
|
365
|
-
RPCMethod: () => exports.RPCMethod,
|
|
366
|
-
ShareAccess: () => exports.ShareAccess,
|
|
367
|
-
SharePermission: () => exports.SharePermission,
|
|
368
|
-
ShareViewLevel: () => exports.ShareViewLevel,
|
|
369
|
-
SlideDeckFormat: () => exports.SlideDeckFormat,
|
|
370
|
-
SlideDeckLength: () => exports.SlideDeckLength,
|
|
371
|
-
SourceStatusCode: () => SourceStatusCode,
|
|
372
|
-
VideoFormat: () => exports.VideoFormat,
|
|
373
|
-
VideoStyle: () => exports.VideoStyle,
|
|
374
|
-
artifactStatusFromCode: () => artifactStatusFromCode,
|
|
375
|
-
artifactTypeFromCode: () => artifactTypeFromCode,
|
|
376
|
-
sourceStatusFromCode: () => sourceStatusFromCode,
|
|
377
|
-
sourceTypeFromCode: () => sourceTypeFromCode
|
|
378
|
-
});
|
|
379
|
-
function sourceTypeFromCode(code) {
|
|
380
|
-
if (code == null) return "unknown";
|
|
381
|
-
return SOURCE_TYPE_MAP[code] ?? "unknown";
|
|
382
|
-
}
|
|
383
|
-
function artifactTypeFromCode(typeCode, variant) {
|
|
384
|
-
if (typeCode === 4) {
|
|
385
|
-
if (variant === 1) return "flashcards";
|
|
386
|
-
if (variant === 2) return "quiz";
|
|
387
|
-
return "unknown";
|
|
388
|
-
}
|
|
389
|
-
return ARTIFACT_TYPE_MAP[typeCode] ?? "unknown";
|
|
390
|
-
}
|
|
391
|
-
function artifactStatusFromCode(code) {
|
|
392
|
-
return ARTIFACT_STATUS_MAP[code] ?? "unknown";
|
|
393
|
-
}
|
|
394
|
-
function sourceStatusFromCode(code) {
|
|
395
|
-
return SOURCE_STATUS_MAP[code] ?? "unknown";
|
|
396
|
-
}
|
|
397
|
-
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.ShareAccess = void 0; exports.ShareViewLevel = void 0; exports.SharePermission = void 0;
|
|
398
|
-
var init_enums = __esm({
|
|
399
|
-
"src/types/enums.ts"() {
|
|
400
|
-
exports.RPCMethod = {
|
|
401
|
-
// Notebook
|
|
402
|
-
LIST_NOTEBOOKS: "wXbhsf",
|
|
403
|
-
CREATE_NOTEBOOK: "CCqFvf",
|
|
404
|
-
GET_NOTEBOOK: "rLM1Ne",
|
|
405
|
-
RENAME_NOTEBOOK: "s0tc2d",
|
|
406
|
-
DELETE_NOTEBOOK: "WWINqb",
|
|
407
|
-
// Sources
|
|
408
|
-
ADD_SOURCE: "izAoDd",
|
|
409
|
-
ADD_SOURCE_FILE: "o4cbdc",
|
|
410
|
-
DELETE_SOURCE: "tGMBJ",
|
|
411
|
-
GET_SOURCE: "hizoJc",
|
|
412
|
-
REFRESH_SOURCE: "FLmJqe",
|
|
413
|
-
CHECK_SOURCE_FRESHNESS: "yR9Yof",
|
|
414
|
-
UPDATE_SOURCE: "b7Wfje",
|
|
415
|
-
// Summary
|
|
416
|
-
SUMMARIZE: "VfAZjd",
|
|
417
|
-
GET_SOURCE_GUIDE: "tr032e",
|
|
418
|
-
GET_SUGGESTED_REPORTS: "ciyUvf",
|
|
419
|
-
// Artifacts
|
|
420
|
-
CREATE_ARTIFACT: "R7cb6c",
|
|
421
|
-
LIST_ARTIFACTS: "gArtLc",
|
|
422
|
-
DELETE_ARTIFACT: "V5N4be",
|
|
423
|
-
RENAME_ARTIFACT: "rc3d8d",
|
|
424
|
-
EXPORT_ARTIFACT: "Krh3pd",
|
|
425
|
-
SHARE_ARTIFACT: "RGP97b",
|
|
426
|
-
GET_INTERACTIVE_HTML: "v9rmvd",
|
|
427
|
-
REVISE_SLIDE: "KmcKPe",
|
|
428
|
-
// Research
|
|
429
|
-
START_FAST_RESEARCH: "Ljjv0c",
|
|
430
|
-
START_DEEP_RESEARCH: "QA9ei",
|
|
431
|
-
POLL_RESEARCH: "e3bVqc",
|
|
432
|
-
IMPORT_RESEARCH: "LBwxtb",
|
|
433
|
-
// Notes / Mind Maps
|
|
434
|
-
GENERATE_MIND_MAP: "yyryJe",
|
|
435
|
-
CREATE_NOTE: "CYK0Xb",
|
|
436
|
-
GET_NOTES_AND_MIND_MAPS: "cFji9",
|
|
437
|
-
UPDATE_NOTE: "cYAfTb",
|
|
438
|
-
DELETE_NOTE: "AH0mwd",
|
|
439
|
-
// Conversation
|
|
440
|
-
GET_LAST_CONVERSATION_ID: "hPTbtc",
|
|
441
|
-
GET_CONVERSATION_TURNS: "khqZz",
|
|
442
|
-
// Sharing
|
|
443
|
-
SHARE_NOTEBOOK: "QDyure",
|
|
444
|
-
GET_SHARE_STATUS: "JFMDGd",
|
|
445
|
-
// Misc
|
|
446
|
-
REMOVE_RECENTLY_VIEWED: "fejl7e",
|
|
447
|
-
GET_USER_SETTINGS: "ZwVcOc",
|
|
448
|
-
SET_USER_SETTINGS: "hT54vc"
|
|
449
|
-
};
|
|
450
|
-
exports.ArtifactTypeCode = {
|
|
451
|
-
AUDIO: 1,
|
|
452
|
-
REPORT: 2,
|
|
453
|
-
VIDEO: 3,
|
|
454
|
-
QUIZ: 4,
|
|
455
|
-
MIND_MAP: 5,
|
|
456
|
-
INFOGRAPHIC: 7,
|
|
457
|
-
SLIDE_DECK: 8,
|
|
458
|
-
DATA_TABLE: 9
|
|
459
|
-
};
|
|
460
|
-
ArtifactStatusCode = {
|
|
461
|
-
PROCESSING: 1,
|
|
462
|
-
PENDING: 2,
|
|
463
|
-
COMPLETED: 3,
|
|
464
|
-
FAILED: 4
|
|
465
|
-
};
|
|
466
|
-
SourceStatusCode = {
|
|
467
|
-
PROCESSING: 1,
|
|
468
|
-
READY: 2,
|
|
469
|
-
ERROR: 3,
|
|
470
|
-
PREPARING: 5
|
|
471
|
-
};
|
|
472
|
-
exports.AudioFormat = {
|
|
473
|
-
DEEP_DIVE: 1,
|
|
474
|
-
BRIEF: 2,
|
|
475
|
-
CRITIQUE: 3,
|
|
476
|
-
DEBATE: 4
|
|
477
|
-
};
|
|
478
|
-
exports.AudioLength = {
|
|
479
|
-
SHORT: 1,
|
|
480
|
-
DEFAULT: 2,
|
|
481
|
-
LONG: 3
|
|
482
|
-
};
|
|
483
|
-
exports.VideoFormat = {
|
|
484
|
-
EXPLAINER: 1,
|
|
485
|
-
BRIEF: 2,
|
|
486
|
-
CINEMATIC: 3
|
|
487
|
-
};
|
|
488
|
-
exports.VideoStyle = {
|
|
489
|
-
AUTO_SELECT: 1,
|
|
490
|
-
CUSTOM: 2,
|
|
491
|
-
CLASSIC: 3,
|
|
492
|
-
WHITEBOARD: 4,
|
|
493
|
-
KAWAII: 5,
|
|
494
|
-
ANIME: 6,
|
|
495
|
-
WATERCOLOR: 7,
|
|
496
|
-
RETRO_PRINT: 8,
|
|
497
|
-
HERITAGE: 9,
|
|
498
|
-
PAPER_CRAFT: 10
|
|
499
|
-
};
|
|
500
|
-
exports.QuizQuantity = {
|
|
501
|
-
FEWER: 1,
|
|
502
|
-
STANDARD: 2,
|
|
503
|
-
MORE: 2
|
|
504
|
-
// API limitation: same as STANDARD
|
|
505
|
-
};
|
|
506
|
-
exports.QuizDifficulty = {
|
|
507
|
-
EASY: 1,
|
|
508
|
-
MEDIUM: 2,
|
|
509
|
-
HARD: 3
|
|
510
|
-
};
|
|
511
|
-
exports.InfographicOrientation = {
|
|
512
|
-
LANDSCAPE: 1,
|
|
513
|
-
PORTRAIT: 2,
|
|
514
|
-
SQUARE: 3
|
|
515
|
-
};
|
|
516
|
-
exports.InfographicDetail = {
|
|
517
|
-
CONCISE: 1,
|
|
518
|
-
STANDARD: 2,
|
|
519
|
-
DETAILED: 3
|
|
520
|
-
};
|
|
521
|
-
exports.InfographicStyle = {
|
|
522
|
-
AUTO_SELECT: 1,
|
|
523
|
-
SKETCH_NOTE: 2,
|
|
524
|
-
PROFESSIONAL: 3,
|
|
525
|
-
BENTO_GRID: 4,
|
|
526
|
-
EDITORIAL: 5,
|
|
527
|
-
INSTRUCTIONAL: 6,
|
|
528
|
-
BRICKS: 7,
|
|
529
|
-
CLAY: 8,
|
|
530
|
-
ANIME: 9,
|
|
531
|
-
KAWAII: 10,
|
|
532
|
-
SCIENTIFIC: 11
|
|
533
|
-
};
|
|
534
|
-
exports.SlideDeckFormat = {
|
|
535
|
-
DETAILED_DECK: 1,
|
|
536
|
-
PRESENTER_SLIDES: 2
|
|
537
|
-
};
|
|
538
|
-
exports.SlideDeckLength = {
|
|
539
|
-
DEFAULT: 1,
|
|
540
|
-
SHORT: 2
|
|
541
|
-
};
|
|
542
|
-
exports.ExportType = {
|
|
543
|
-
DOCS: 1,
|
|
544
|
-
SHEETS: 2
|
|
545
|
-
};
|
|
546
|
-
SOURCE_TYPE_MAP = {
|
|
547
|
-
1: "google_docs",
|
|
548
|
-
2: "google_slides",
|
|
549
|
-
3: "pdf",
|
|
550
|
-
4: "pasted_text",
|
|
551
|
-
5: "web_page",
|
|
552
|
-
8: "markdown",
|
|
553
|
-
9: "youtube",
|
|
554
|
-
10: "media",
|
|
555
|
-
11: "docx",
|
|
556
|
-
13: "image",
|
|
557
|
-
14: "google_spreadsheet",
|
|
558
|
-
16: "csv"
|
|
559
|
-
};
|
|
560
|
-
ARTIFACT_TYPE_MAP = {
|
|
561
|
-
1: "audio",
|
|
562
|
-
2: "report",
|
|
563
|
-
3: "video",
|
|
564
|
-
5: "mind_map",
|
|
565
|
-
7: "infographic",
|
|
566
|
-
8: "slide_deck",
|
|
567
|
-
9: "data_table"
|
|
568
|
-
};
|
|
569
|
-
ARTIFACT_STATUS_MAP = {
|
|
570
|
-
1: "in_progress",
|
|
571
|
-
2: "pending",
|
|
572
|
-
3: "completed",
|
|
573
|
-
4: "failed"
|
|
574
|
-
};
|
|
575
|
-
SOURCE_STATUS_MAP = {
|
|
576
|
-
1: "processing",
|
|
577
|
-
2: "ready",
|
|
578
|
-
3: "error",
|
|
579
|
-
5: "preparing"
|
|
580
|
-
};
|
|
581
|
-
exports.ShareAccess = {
|
|
582
|
-
/** Only explicitly shared users can access */
|
|
583
|
-
RESTRICTED: 0,
|
|
584
|
-
/** Anyone with the link can access */
|
|
585
|
-
ANYONE_WITH_LINK: 1
|
|
586
|
-
};
|
|
587
|
-
exports.ShareViewLevel = {
|
|
588
|
-
/** Chat + sources + notes */
|
|
589
|
-
FULL_NOTEBOOK: 0,
|
|
590
|
-
/** Chat interface only */
|
|
591
|
-
CHAT_ONLY: 1
|
|
592
|
-
};
|
|
593
|
-
exports.SharePermission = {
|
|
594
|
-
OWNER: 1,
|
|
595
|
-
EDITOR: 2,
|
|
596
|
-
VIEWER: 3,
|
|
597
|
-
/** Internal: remove user from share list */
|
|
598
|
-
_REMOVE: 4
|
|
599
|
-
};
|
|
600
|
-
}
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
// src/client.ts
|
|
604
|
-
init_auth();
|
|
605
|
-
|
|
606
|
-
// src/rpc/core.ts
|
|
607
|
-
init_errors();
|
|
608
|
-
|
|
609
|
-
// src/rpc/encoder.ts
|
|
610
|
-
function encodeRPCRequest(methodId, params) {
|
|
611
|
-
const paramsJson = JSON.stringify(params);
|
|
612
|
-
return [[[methodId, paramsJson, null, "generic"]]];
|
|
613
|
-
}
|
|
614
|
-
function buildRequestBody(rpcRequest, csrfToken) {
|
|
615
|
-
const fReq = encodeURIComponent(JSON.stringify(rpcRequest));
|
|
616
|
-
const at = encodeURIComponent(csrfToken);
|
|
617
|
-
return `f.req=${fReq}&at=${at}&`;
|
|
618
|
-
}
|
|
619
|
-
function buildUrlParams(methodId, sessionId, sourcePath = "/") {
|
|
620
|
-
return new URLSearchParams({
|
|
621
|
-
rpcids: methodId,
|
|
622
|
-
"source-path": sourcePath,
|
|
623
|
-
"f.sid": sessionId,
|
|
624
|
-
hl: "en",
|
|
625
|
-
rt: "c"
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// src/rpc/decoder.ts
|
|
630
|
-
init_errors();
|
|
631
|
-
function stripAntiXSSI(response) {
|
|
632
|
-
if (response.startsWith(")]}'")) {
|
|
633
|
-
const match = /\)\]\}'\r?\n/.exec(response);
|
|
634
|
-
if (match) return response.slice(match[0].length);
|
|
635
|
-
}
|
|
636
|
-
return response;
|
|
637
|
-
}
|
|
638
|
-
function parseChunkedResponse(response) {
|
|
639
|
-
if (!response || !response.trim()) return [];
|
|
640
|
-
const chunks = [];
|
|
641
|
-
let skippedCount = 0;
|
|
642
|
-
const lines = response.trim().split("\n");
|
|
643
|
-
let i = 0;
|
|
644
|
-
while (i < lines.length) {
|
|
645
|
-
const line = (lines[i] ?? "").trim();
|
|
646
|
-
if (!line) {
|
|
647
|
-
i++;
|
|
648
|
-
continue;
|
|
649
|
-
}
|
|
650
|
-
if (/^\d+$/.test(line)) {
|
|
651
|
-
i++;
|
|
652
|
-
if (i < lines.length) {
|
|
653
|
-
try {
|
|
654
|
-
const chunk = JSON.parse(lines[i] ?? "");
|
|
655
|
-
chunks.push(chunk);
|
|
656
|
-
} catch {
|
|
657
|
-
skippedCount++;
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
i++;
|
|
661
|
-
} else {
|
|
662
|
-
try {
|
|
663
|
-
const chunk = JSON.parse(line);
|
|
664
|
-
chunks.push(chunk);
|
|
665
|
-
} catch {
|
|
666
|
-
skippedCount++;
|
|
667
|
-
}
|
|
668
|
-
i++;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
if (skippedCount > 0 && lines.length > 0) {
|
|
672
|
-
const errorRate = skippedCount / lines.length;
|
|
673
|
-
if (errorRate > 0.1) {
|
|
674
|
-
throw new exports.RPCError(
|
|
675
|
-
`Response parsing failed: ${skippedCount} of ${lines.length} chunks malformed`,
|
|
676
|
-
{ rawResponse: response.slice(0, 500) }
|
|
677
|
-
);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
return chunks;
|
|
681
|
-
}
|
|
682
|
-
function containsUserDisplayableError(obj) {
|
|
683
|
-
if (typeof obj === "string") return obj.includes("UserDisplayableError");
|
|
684
|
-
if (Array.isArray(obj)) return obj.some(containsUserDisplayableError);
|
|
685
|
-
if (obj !== null && typeof obj === "object") {
|
|
686
|
-
return Object.values(obj).some(containsUserDisplayableError);
|
|
687
|
-
}
|
|
688
|
-
return false;
|
|
689
|
-
}
|
|
690
|
-
function collectRPCIds(chunks) {
|
|
691
|
-
const ids = [];
|
|
692
|
-
for (const chunk of chunks) {
|
|
693
|
-
if (!Array.isArray(chunk)) continue;
|
|
694
|
-
const items = Array.isArray(chunk[0]) ? chunk : [chunk];
|
|
695
|
-
for (const item of items) {
|
|
696
|
-
if (!Array.isArray(item) || item.length < 2) continue;
|
|
697
|
-
if ((item[0] === "wrb.fr" || item[0] === "er") && typeof item[1] === "string") {
|
|
698
|
-
ids.push(item[1]);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
return ids;
|
|
703
|
-
}
|
|
704
|
-
function extractRPCResult(chunks, rpcId) {
|
|
705
|
-
for (const chunk of chunks) {
|
|
706
|
-
if (!Array.isArray(chunk)) continue;
|
|
707
|
-
const items = Array.isArray(chunk[0]) ? chunk : [chunk];
|
|
708
|
-
for (const item of items) {
|
|
709
|
-
if (!Array.isArray(item) || item.length < 3) continue;
|
|
710
|
-
if (item[0] === "er" && item[1] === rpcId) {
|
|
711
|
-
const code = item[2];
|
|
712
|
-
let msg = "Unknown error";
|
|
713
|
-
if (typeof code === "number") {
|
|
714
|
-
if (code === 429) msg = "API rate limit exceeded. Please wait before retrying.";
|
|
715
|
-
else if (code === 401 || code === 403) msg = "Authentication required or forbidden.";
|
|
716
|
-
else if (code === 404) msg = "Resource not found.";
|
|
717
|
-
else if (code >= 500) msg = `Server error ${code}. Try again later.`;
|
|
718
|
-
else msg = `Error code: ${code}`;
|
|
719
|
-
} else if (typeof code === "string") {
|
|
720
|
-
msg = code;
|
|
721
|
-
}
|
|
722
|
-
throw new exports.RPCError(msg, { methodId: rpcId, rpcCode: code });
|
|
723
|
-
}
|
|
724
|
-
if (item[0] === "wrb.fr" && item[1] === rpcId) {
|
|
725
|
-
const resultData = item[2];
|
|
726
|
-
if (resultData === null && item.length > 5 && item[5] != null) {
|
|
727
|
-
if (containsUserDisplayableError(item[5])) {
|
|
728
|
-
throw new exports.RateLimitError(
|
|
729
|
-
"API rate limit or quota exceeded. Please wait before retrying.",
|
|
730
|
-
{ methodId: rpcId, rpcCode: "USER_DISPLAYABLE_ERROR" }
|
|
731
|
-
);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
if (typeof resultData === "string") {
|
|
735
|
-
try {
|
|
736
|
-
return JSON.parse(resultData);
|
|
737
|
-
} catch {
|
|
738
|
-
return resultData;
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
return resultData;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
return void 0;
|
|
746
|
-
}
|
|
747
|
-
function decodeResponse(rawResponse, rpcId, allowNull = false) {
|
|
748
|
-
const cleaned = stripAntiXSSI(rawResponse);
|
|
749
|
-
const chunks = parseChunkedResponse(cleaned);
|
|
750
|
-
const responsePreview = cleaned.slice(0, 500);
|
|
751
|
-
const foundIds = collectRPCIds(chunks);
|
|
752
|
-
let result;
|
|
753
|
-
try {
|
|
754
|
-
result = extractRPCResult(chunks, rpcId);
|
|
755
|
-
} catch (e) {
|
|
756
|
-
if (e instanceof exports.RPCError && e.foundIds.length === 0) {
|
|
757
|
-
throw new exports.RPCError(e.message, {
|
|
758
|
-
methodId: e.methodId,
|
|
759
|
-
rpcCode: e.rpcCode,
|
|
760
|
-
foundIds,
|
|
761
|
-
rawResponse: responsePreview
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
throw e;
|
|
765
|
-
}
|
|
766
|
-
if (result === void 0 && !allowNull) {
|
|
767
|
-
if (foundIds.length > 0 && !foundIds.includes(rpcId)) {
|
|
768
|
-
throw new exports.RPCError(
|
|
769
|
-
`No result for RPC ID '${rpcId}'. Response has IDs: ${foundIds.join(", ")}. Method ID may have changed.`,
|
|
770
|
-
{ methodId: rpcId, foundIds, rawResponse: responsePreview }
|
|
771
|
-
);
|
|
772
|
-
}
|
|
773
|
-
throw new exports.RPCError(`No result found for RPC ID: ${rpcId} (${chunks.length} chunks parsed)`, {
|
|
774
|
-
methodId: rpcId,
|
|
775
|
-
foundIds,
|
|
776
|
-
rawResponse: responsePreview
|
|
777
|
-
});
|
|
778
|
-
}
|
|
779
|
-
return result ?? null;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
// src/rpc/core.ts
|
|
783
|
-
var BATCHEXECUTE_URL = "https://notebooklm.google.com/_/LabsTailwindUi/data/batchexecute";
|
|
784
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
785
|
-
var RPCCore = class {
|
|
786
|
-
auth;
|
|
787
|
-
timeoutMs;
|
|
788
|
-
constructor(auth, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
789
|
-
this.auth = auth;
|
|
790
|
-
this.timeoutMs = timeoutMs;
|
|
791
|
-
}
|
|
792
|
-
async call(methodId, params, opts = {}) {
|
|
793
|
-
const sourcePath = opts.sourcePath ?? "/";
|
|
794
|
-
const allowNull = opts.allowNull ?? false;
|
|
795
|
-
const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
|
|
796
|
-
const rpcRequest = encodeRPCRequest(methodId, params);
|
|
797
|
-
const body = buildRequestBody(rpcRequest, this.auth.csrfToken);
|
|
798
|
-
const urlParams = buildUrlParams(methodId, this.auth.sessionId, sourcePath);
|
|
799
|
-
const url = `${BATCHEXECUTE_URL}?${urlParams.toString()}`;
|
|
800
|
-
const controller = new AbortController();
|
|
801
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
802
|
-
let response;
|
|
803
|
-
try {
|
|
804
|
-
response = await fetch(url, {
|
|
805
|
-
method: "POST",
|
|
806
|
-
headers: {
|
|
807
|
-
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
808
|
-
Cookie: this.auth.cookieHeader
|
|
809
|
-
},
|
|
810
|
-
body,
|
|
811
|
-
signal: controller.signal
|
|
812
|
-
});
|
|
813
|
-
} catch (e) {
|
|
814
|
-
clearTimeout(timer);
|
|
815
|
-
if (e instanceof Error && e.name === "AbortError") {
|
|
816
|
-
throw new exports.RPCTimeoutError(`Request timed out calling ${methodId}`, {
|
|
817
|
-
methodId,
|
|
818
|
-
originalError: e
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
throw new exports.NetworkError(`Request failed calling ${methodId}: ${String(e)}`, {
|
|
822
|
-
methodId,
|
|
823
|
-
originalError: e instanceof Error ? e : void 0
|
|
824
|
-
});
|
|
825
|
-
} finally {
|
|
826
|
-
clearTimeout(timer);
|
|
827
|
-
}
|
|
828
|
-
if (!response.ok) {
|
|
829
|
-
const status = response.status;
|
|
830
|
-
if (status === 429) {
|
|
831
|
-
const retryAfterHeader = response.headers.get("retry-after");
|
|
832
|
-
const retryAfter = retryAfterHeader ? parseInt(retryAfterHeader, 10) : void 0;
|
|
833
|
-
throw new exports.RateLimitError(`API rate limit exceeded calling ${methodId}`, {
|
|
834
|
-
methodId,
|
|
835
|
-
retryAfter: isNaN(retryAfter ?? NaN) ? void 0 : retryAfter
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
if (status === 401 || status === 403) {
|
|
839
|
-
throw new exports.AuthError(`HTTP ${status} calling ${methodId}: authentication required`, {
|
|
840
|
-
methodId
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
if (status >= 500) {
|
|
844
|
-
throw new exports.ServerError(`Server error ${status} calling ${methodId}`, {
|
|
845
|
-
methodId,
|
|
846
|
-
statusCode: status
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
if (status >= 400) {
|
|
850
|
-
throw new exports.ClientError(`Client error ${status} calling ${methodId}`, {
|
|
851
|
-
methodId,
|
|
852
|
-
statusCode: status
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
|
-
throw new exports.RPCError(`HTTP ${status} calling ${methodId}`, { methodId });
|
|
856
|
-
}
|
|
857
|
-
const text = await response.text();
|
|
858
|
-
return decodeResponse(text, methodId, allowNull);
|
|
859
|
-
}
|
|
860
|
-
/** Extract source IDs from a notebook (used by chat/artifact APIs). */
|
|
861
|
-
async getSourceIds(notebookId) {
|
|
862
|
-
const params = [notebookId, null, [2], null, 0];
|
|
863
|
-
const { RPCMethod: RPCMethod2 } = await Promise.resolve().then(() => (init_enums(), enums_exports));
|
|
864
|
-
const data = await this.call(RPCMethod2.GET_NOTEBOOK, params, {
|
|
865
|
-
sourcePath: `/notebook/${notebookId}`
|
|
866
|
-
});
|
|
867
|
-
const sourceIds = [];
|
|
868
|
-
if (!Array.isArray(data) || !data.length) return sourceIds;
|
|
869
|
-
try {
|
|
870
|
-
const nbInfo = data[0];
|
|
871
|
-
if (!Array.isArray(nbInfo) || nbInfo.length <= 1) return sourceIds;
|
|
872
|
-
const sources = nbInfo[1];
|
|
873
|
-
if (!Array.isArray(sources)) return sourceIds;
|
|
874
|
-
for (const src of sources) {
|
|
875
|
-
if (!Array.isArray(src) || !src.length) continue;
|
|
876
|
-
const first = src[0];
|
|
877
|
-
if (Array.isArray(first) && first.length > 0 && typeof first[0] === "string") {
|
|
878
|
-
sourceIds.push(first[0]);
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
} catch {
|
|
882
|
-
}
|
|
883
|
-
return sourceIds;
|
|
884
|
-
}
|
|
885
|
-
};
|
|
886
|
-
|
|
887
|
-
// src/api/notebooks.ts
|
|
603
|
+
// src/api/artifacts.ts
|
|
888
604
|
init_enums();
|
|
605
|
+
init_errors();
|
|
889
606
|
|
|
890
607
|
// src/types/models.ts
|
|
891
608
|
init_enums();
|
|
@@ -1010,286 +727,14 @@ function parseNote(data) {
|
|
|
1010
727
|
}
|
|
1011
728
|
if (Array.isArray(data[4]) && typeof data[4][0] === "number") {
|
|
1012
729
|
try {
|
|
1013
|
-
updatedAt = new Date(data[4][0] * 1e3);
|
|
1014
|
-
} catch {
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
return { id, title, content, createdAt, updatedAt };
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
// src/api/notebooks.ts
|
|
1021
|
-
var NotebooksAPI = class {
|
|
1022
|
-
constructor(rpc) {
|
|
1023
|
-
this.rpc = rpc;
|
|
1024
|
-
}
|
|
1025
|
-
async list() {
|
|
1026
|
-
const params = [null, 1, null, [2]];
|
|
1027
|
-
const result = await this.rpc.call(exports.RPCMethod.LIST_NOTEBOOKS, params);
|
|
1028
|
-
if (!Array.isArray(result) || !result.length) return [];
|
|
1029
|
-
const raw = Array.isArray(result[0]) ? result[0] : result;
|
|
1030
|
-
return raw.map((nb) => parseNotebook(nb));
|
|
1031
|
-
}
|
|
1032
|
-
async create(title) {
|
|
1033
|
-
const params = [title, null, null, [2], [1]];
|
|
1034
|
-
const result = await this.rpc.call(exports.RPCMethod.CREATE_NOTEBOOK, params);
|
|
1035
|
-
return parseNotebook(result);
|
|
1036
|
-
}
|
|
1037
|
-
async get(notebookId) {
|
|
1038
|
-
const params = [notebookId, null, [2], null, 0];
|
|
1039
|
-
const result = await this.rpc.call(exports.RPCMethod.GET_NOTEBOOK, params, {
|
|
1040
|
-
sourcePath: `/notebook/${notebookId}`
|
|
1041
|
-
});
|
|
1042
|
-
const data = Array.isArray(result) && result.length ? result[0] : result;
|
|
1043
|
-
return parseNotebook(data);
|
|
1044
|
-
}
|
|
1045
|
-
async delete(notebookId) {
|
|
1046
|
-
const params = [[notebookId], [2]];
|
|
1047
|
-
await this.rpc.call(exports.RPCMethod.DELETE_NOTEBOOK, params);
|
|
1048
|
-
return true;
|
|
1049
|
-
}
|
|
1050
|
-
async rename(notebookId, newTitle) {
|
|
1051
|
-
const params = [notebookId, [[null, null, null, [null, newTitle]]]];
|
|
1052
|
-
await this.rpc.call(exports.RPCMethod.RENAME_NOTEBOOK, params, {
|
|
1053
|
-
sourcePath: "/",
|
|
1054
|
-
allowNull: true
|
|
1055
|
-
});
|
|
1056
|
-
return this.get(notebookId);
|
|
1057
|
-
}
|
|
1058
|
-
async getSummary(notebookId) {
|
|
1059
|
-
const params = [notebookId, [2]];
|
|
1060
|
-
const result = await this.rpc.call(exports.RPCMethod.SUMMARIZE, params, {
|
|
1061
|
-
sourcePath: `/notebook/${notebookId}`
|
|
1062
|
-
});
|
|
1063
|
-
try {
|
|
1064
|
-
if (Array.isArray(result)) {
|
|
1065
|
-
const val = result[0]?.[0]?.[0];
|
|
1066
|
-
return typeof val === "string" ? val : "";
|
|
1067
|
-
}
|
|
1068
|
-
} catch {
|
|
1069
|
-
}
|
|
1070
|
-
return "";
|
|
1071
|
-
}
|
|
1072
|
-
async getDescription(notebookId) {
|
|
1073
|
-
const params = [notebookId, [2]];
|
|
1074
|
-
const result = await this.rpc.call(exports.RPCMethod.SUMMARIZE, params, {
|
|
1075
|
-
sourcePath: `/notebook/${notebookId}`
|
|
1076
|
-
});
|
|
1077
|
-
let summary = "";
|
|
1078
|
-
const suggestedTopics = [];
|
|
1079
|
-
try {
|
|
1080
|
-
if (Array.isArray(result)) {
|
|
1081
|
-
const outer = result[0];
|
|
1082
|
-
if (Array.isArray(outer)) {
|
|
1083
|
-
const summaryVal = outer[0]?.[0];
|
|
1084
|
-
if (typeof summaryVal === "string") summary = summaryVal;
|
|
1085
|
-
const topicsList = outer[1]?.[0];
|
|
1086
|
-
if (Array.isArray(topicsList)) {
|
|
1087
|
-
for (const t of topicsList) {
|
|
1088
|
-
const question = typeof t[0] === "string" ? t[0] : "";
|
|
1089
|
-
const prompt = typeof t[1] === "string" ? t[1] : "";
|
|
1090
|
-
suggestedTopics.push({ question, prompt });
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
} catch {
|
|
1096
|
-
}
|
|
1097
|
-
return { summary, suggestedTopics };
|
|
1098
|
-
}
|
|
1099
|
-
};
|
|
1100
|
-
|
|
1101
|
-
// src/api/sources.ts
|
|
1102
|
-
init_enums();
|
|
1103
|
-
init_errors();
|
|
1104
|
-
var UPLOAD_URL = "https://notebooklm.google.com/upload/_/";
|
|
1105
|
-
var SourcesAPI = class {
|
|
1106
|
-
constructor(rpc, auth) {
|
|
1107
|
-
this.rpc = rpc;
|
|
1108
|
-
this.auth = auth;
|
|
1109
|
-
}
|
|
1110
|
-
async list(notebookId) {
|
|
1111
|
-
const params = [notebookId, null, [2], null, 0];
|
|
1112
|
-
const notebook = await this.rpc.call(exports.RPCMethod.GET_NOTEBOOK, params, {
|
|
1113
|
-
sourcePath: `/notebook/${notebookId}`
|
|
1114
|
-
});
|
|
1115
|
-
if (!Array.isArray(notebook) || !notebook.length) return [];
|
|
1116
|
-
const nbInfo = notebook[0];
|
|
1117
|
-
if (!Array.isArray(nbInfo) || nbInfo.length <= 1) return [];
|
|
1118
|
-
const sourcesList = nbInfo[1];
|
|
1119
|
-
if (!Array.isArray(sourcesList)) return [];
|
|
1120
|
-
return sourcesList.filter((s) => Array.isArray(s) && s.length > 0).map((s) => parseSource(s));
|
|
1121
|
-
}
|
|
1122
|
-
async get(notebookId, sourceId) {
|
|
1123
|
-
const sources = await this.list(notebookId);
|
|
1124
|
-
return sources.find((s) => s.id === sourceId) ?? null;
|
|
1125
|
-
}
|
|
1126
|
-
async addUrl(notebookId, url, opts = {}) {
|
|
1127
|
-
const params = [notebookId, [[url]], null, null, [2]];
|
|
1128
|
-
const result = await this.rpc.call(exports.RPCMethod.ADD_SOURCE, params, {
|
|
1129
|
-
sourcePath: `/notebook/${notebookId}`
|
|
1130
|
-
});
|
|
1131
|
-
const sourceId = extractSourceId(result);
|
|
1132
|
-
if (opts.waitUntilReady) {
|
|
1133
|
-
return this.waitUntilReady(notebookId, sourceId, opts.waitTimeout);
|
|
1134
|
-
}
|
|
1135
|
-
return {
|
|
1136
|
-
id: sourceId,
|
|
1137
|
-
title: url,
|
|
1138
|
-
url,
|
|
1139
|
-
kind: "web_page",
|
|
1140
|
-
createdAt: null,
|
|
1141
|
-
status: "processing",
|
|
1142
|
-
_typeCode: null
|
|
1143
|
-
};
|
|
1144
|
-
}
|
|
1145
|
-
async addText(notebookId, text, title, opts = {}) {
|
|
1146
|
-
const params = [notebookId, null, [[null, null, null, text, title ?? null]], null, [2]];
|
|
1147
|
-
const result = await this.rpc.call(exports.RPCMethod.ADD_SOURCE, params, {
|
|
1148
|
-
sourcePath: `/notebook/${notebookId}`
|
|
1149
|
-
});
|
|
1150
|
-
const sourceId = extractSourceId(result);
|
|
1151
|
-
if (opts.waitUntilReady) {
|
|
1152
|
-
return this.waitUntilReady(notebookId, sourceId, opts.waitTimeout);
|
|
1153
|
-
}
|
|
1154
|
-
return {
|
|
1155
|
-
id: sourceId,
|
|
1156
|
-
title: title ?? null,
|
|
1157
|
-
url: null,
|
|
1158
|
-
kind: "pasted_text",
|
|
1159
|
-
createdAt: null,
|
|
1160
|
-
status: "processing",
|
|
1161
|
-
_typeCode: null
|
|
1162
|
-
};
|
|
1163
|
-
}
|
|
1164
|
-
async addFile(notebookId, filePath, mimeType, opts = {}) {
|
|
1165
|
-
const fileData = fs.readFileSync(filePath);
|
|
1166
|
-
const fileName = filePath.split("/").pop() ?? "file";
|
|
1167
|
-
return this.addFileBuffer(notebookId, fileData, fileName, mimeType, opts);
|
|
1168
|
-
}
|
|
1169
|
-
async addFileBuffer(notebookId, data, fileName, mimeType, opts = {}) {
|
|
1170
|
-
const uploadUrl = await this.uploadFile(notebookId, data, fileName, mimeType);
|
|
1171
|
-
const params = [notebookId, null, null, [[uploadUrl, fileName, mimeType]], [2]];
|
|
1172
|
-
const result = await this.rpc.call(exports.RPCMethod.ADD_SOURCE_FILE, params, {
|
|
1173
|
-
sourcePath: `/notebook/${notebookId}`
|
|
1174
|
-
});
|
|
1175
|
-
const sourceId = extractSourceId(result);
|
|
1176
|
-
if (opts.waitUntilReady) {
|
|
1177
|
-
return this.waitUntilReady(notebookId, sourceId, opts.waitTimeout);
|
|
1178
|
-
}
|
|
1179
|
-
return {
|
|
1180
|
-
id: sourceId,
|
|
1181
|
-
title: fileName,
|
|
1182
|
-
url: null,
|
|
1183
|
-
kind: "pdf",
|
|
1184
|
-
createdAt: null,
|
|
1185
|
-
status: "processing",
|
|
1186
|
-
_typeCode: null
|
|
1187
|
-
};
|
|
1188
|
-
}
|
|
1189
|
-
async uploadFile(notebookId, data, fileName, mimeType) {
|
|
1190
|
-
const params = new URLSearchParams({
|
|
1191
|
-
"source-path": `/notebook/${notebookId}`,
|
|
1192
|
-
upload_id: `${Date.now()}`,
|
|
1193
|
-
upload_protocol: "resumable"
|
|
1194
|
-
});
|
|
1195
|
-
const initResp = await fetch(`${UPLOAD_URL}?${params}`, {
|
|
1196
|
-
method: "POST",
|
|
1197
|
-
headers: {
|
|
1198
|
-
Cookie: this.auth.cookieHeader,
|
|
1199
|
-
"X-Goog-Upload-Command": "start",
|
|
1200
|
-
"X-Goog-Upload-Header-Content-Length": String(data.length),
|
|
1201
|
-
"X-Goog-Upload-Header-Content-Type": mimeType,
|
|
1202
|
-
"X-Upload-Content-Type": mimeType,
|
|
1203
|
-
"Content-Type": "application/json"
|
|
1204
|
-
},
|
|
1205
|
-
body: JSON.stringify({ title: fileName })
|
|
1206
|
-
});
|
|
1207
|
-
if (!initResp.ok) {
|
|
1208
|
-
throw new Error(`Upload initiation failed: HTTP ${initResp.status}`);
|
|
1209
|
-
}
|
|
1210
|
-
const uploadSessionUrl = initResp.headers.get("x-goog-upload-url") ?? `${UPLOAD_URL}?${params}`;
|
|
1211
|
-
const uploadResp = await fetch(uploadSessionUrl, {
|
|
1212
|
-
method: "POST",
|
|
1213
|
-
headers: {
|
|
1214
|
-
Cookie: this.auth.cookieHeader,
|
|
1215
|
-
"X-Goog-Upload-Command": "upload, finalize",
|
|
1216
|
-
"X-Goog-Upload-Offset": "0",
|
|
1217
|
-
"Content-Type": mimeType,
|
|
1218
|
-
"Content-Length": String(data.length)
|
|
1219
|
-
},
|
|
1220
|
-
body: data instanceof Buffer ? data.buffer : data.buffer
|
|
1221
|
-
});
|
|
1222
|
-
if (!uploadResp.ok) {
|
|
1223
|
-
throw new Error(`File upload failed: HTTP ${uploadResp.status}`);
|
|
1224
|
-
}
|
|
1225
|
-
const uploadResult = await uploadResp.text();
|
|
1226
|
-
return uploadResult.trim();
|
|
1227
|
-
}
|
|
1228
|
-
async delete(notebookId, sourceId) {
|
|
1229
|
-
const params = [notebookId, [sourceId], [2]];
|
|
1230
|
-
await this.rpc.call(exports.RPCMethod.DELETE_SOURCE, params, {
|
|
1231
|
-
sourcePath: `/notebook/${notebookId}`,
|
|
1232
|
-
allowNull: true
|
|
1233
|
-
});
|
|
1234
|
-
return true;
|
|
1235
|
-
}
|
|
1236
|
-
async refresh(notebookId, sourceId) {
|
|
1237
|
-
const params = [notebookId, sourceId, [2]];
|
|
1238
|
-
await this.rpc.call(exports.RPCMethod.REFRESH_SOURCE, params, {
|
|
1239
|
-
sourcePath: `/notebook/${notebookId}`,
|
|
1240
|
-
allowNull: true
|
|
1241
|
-
});
|
|
1242
|
-
return true;
|
|
1243
|
-
}
|
|
1244
|
-
async waitUntilReady(notebookId, sourceId, timeout = 120, initialInterval = 1, maxInterval = 10, backoffFactor = 1.5) {
|
|
1245
|
-
const deadline = Date.now() + timeout * 1e3;
|
|
1246
|
-
let interval = initialInterval;
|
|
1247
|
-
let lastStatus;
|
|
1248
|
-
while (Date.now() < deadline) {
|
|
1249
|
-
const source = await this.get(notebookId, sourceId);
|
|
1250
|
-
if (source) {
|
|
1251
|
-
if (source.status === "ready") return source;
|
|
1252
|
-
if (source.status === "error") {
|
|
1253
|
-
throw new exports.SourceProcessingError(sourceId, 3);
|
|
1254
|
-
}
|
|
1255
|
-
lastStatus = source._typeCode ?? void 0;
|
|
1256
|
-
}
|
|
1257
|
-
await sleep(interval * 1e3);
|
|
1258
|
-
interval = Math.min(interval * backoffFactor, maxInterval);
|
|
1259
|
-
}
|
|
1260
|
-
throw new exports.SourceTimeoutError(sourceId, timeout, lastStatus);
|
|
1261
|
-
}
|
|
1262
|
-
};
|
|
1263
|
-
function extractSourceId(result) {
|
|
1264
|
-
if (Array.isArray(result)) {
|
|
1265
|
-
try {
|
|
1266
|
-
const v0 = result[0];
|
|
1267
|
-
if (Array.isArray(v0)) {
|
|
1268
|
-
const v00 = v0[0];
|
|
1269
|
-
if (Array.isArray(v00)) {
|
|
1270
|
-
const v000 = v00[0];
|
|
1271
|
-
if (Array.isArray(v000) && typeof v000[0] === "string") return v000[0];
|
|
1272
|
-
if (typeof v000 === "string") return v000;
|
|
1273
|
-
}
|
|
1274
|
-
if (typeof v00 === "string") return v00;
|
|
1275
|
-
}
|
|
1276
|
-
if (typeof v0 === "string") return v0;
|
|
730
|
+
updatedAt = new Date(data[4][0] * 1e3);
|
|
1277
731
|
} catch {
|
|
1278
732
|
}
|
|
1279
|
-
for (const item of result) {
|
|
1280
|
-
if (typeof item === "string" && item.length > 8) return item;
|
|
1281
|
-
}
|
|
1282
733
|
}
|
|
1283
|
-
|
|
1284
|
-
throw new Error("Could not extract source ID from API response");
|
|
1285
|
-
}
|
|
1286
|
-
function sleep(ms) {
|
|
1287
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
734
|
+
return { id, title, content, createdAt, updatedAt };
|
|
1288
735
|
}
|
|
1289
736
|
|
|
1290
737
|
// src/api/artifacts.ts
|
|
1291
|
-
init_enums();
|
|
1292
|
-
init_errors();
|
|
1293
738
|
function tripleNest(ids) {
|
|
1294
739
|
return ids.map((id) => [[id]]);
|
|
1295
740
|
}
|
|
@@ -1578,7 +1023,7 @@ ${opts.extraInstructions}` : cfg.prompt;
|
|
|
1578
1023
|
if (artifact?.status === "failed") {
|
|
1579
1024
|
throw new exports.ArtifactNotReadyError(artifact.kind, { artifactId, status: "failed" });
|
|
1580
1025
|
}
|
|
1581
|
-
await
|
|
1026
|
+
await sleep(pollInterval * 1e3);
|
|
1582
1027
|
}
|
|
1583
1028
|
throw new exports.ArtifactNotReadyError("artifact", { artifactId, status: "timeout" });
|
|
1584
1029
|
}
|
|
@@ -1676,7 +1121,7 @@ ${opts.extraInstructions}` : cfg.prompt;
|
|
|
1676
1121
|
return { artifactId: null, status: "failed" };
|
|
1677
1122
|
}
|
|
1678
1123
|
};
|
|
1679
|
-
function
|
|
1124
|
+
function sleep(ms) {
|
|
1680
1125
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1681
1126
|
}
|
|
1682
1127
|
var TRUSTED_MEDIA_DOMAINS = [
|
|
@@ -1746,589 +1191,1185 @@ var ChatAPI = class {
|
|
|
1746
1191
|
} catch (e) {
|
|
1747
1192
|
throw new exports.ChatError(`Chat request failed: ${String(e)}`);
|
|
1748
1193
|
}
|
|
1749
|
-
if (!response.ok) throw new exports.ChatError(`Chat request failed: HTTP ${response.status}`);
|
|
1750
|
-
const text = await response.text();
|
|
1751
|
-
const { answer, conversationId: serverConvId, references } = parseStreamingResponse(text);
|
|
1752
|
-
const finalConvId = serverConvId ?? conversationId;
|
|
1753
|
-
const cached = this.conversationCache.get(finalConvId) ?? [];
|
|
1754
|
-
const turnNumber = cached.length + 1;
|
|
1755
|
-
cached.push({ query, answer, turnNumber });
|
|
1756
|
-
this.conversationCache.set(finalConvId, cached);
|
|
1757
|
-
return { answer, conversationId: finalConvId, turnNumber, references };
|
|
1194
|
+
if (!response.ok) throw new exports.ChatError(`Chat request failed: HTTP ${response.status}`);
|
|
1195
|
+
const text = await response.text();
|
|
1196
|
+
const { answer, conversationId: serverConvId, references } = parseStreamingResponse(text);
|
|
1197
|
+
const finalConvId = serverConvId ?? conversationId;
|
|
1198
|
+
const cached = this.conversationCache.get(finalConvId) ?? [];
|
|
1199
|
+
const turnNumber = cached.length + 1;
|
|
1200
|
+
cached.push({ query, answer, turnNumber });
|
|
1201
|
+
this.conversationCache.set(finalConvId, cached);
|
|
1202
|
+
return { answer, conversationId: finalConvId, turnNumber, references };
|
|
1203
|
+
}
|
|
1204
|
+
async getConversationTurns(notebookId, conversationId) {
|
|
1205
|
+
const params = [[], null, null, conversationId, 100];
|
|
1206
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_CONVERSATION_TURNS, params, {
|
|
1207
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1208
|
+
allowNull: true
|
|
1209
|
+
});
|
|
1210
|
+
if (!Array.isArray(result) || !Array.isArray(result[0])) return [];
|
|
1211
|
+
const rawTurns = [...result[0]].reverse();
|
|
1212
|
+
const turns = [];
|
|
1213
|
+
let i = 0;
|
|
1214
|
+
while (i < rawTurns.length) {
|
|
1215
|
+
const turn = rawTurns[i];
|
|
1216
|
+
if (!Array.isArray(turn) || turn.length < 3) {
|
|
1217
|
+
i++;
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
if (turn[2] === 1 && turn.length > 3) {
|
|
1221
|
+
const q = typeof turn[3] === "string" ? turn[3] : "";
|
|
1222
|
+
let a = "";
|
|
1223
|
+
const next = rawTurns[i + 1];
|
|
1224
|
+
if (Array.isArray(next) && next.length > 4 && next[2] === 2) {
|
|
1225
|
+
try {
|
|
1226
|
+
a = String(next[4][0][0] ?? "");
|
|
1227
|
+
} catch {
|
|
1228
|
+
}
|
|
1229
|
+
i++;
|
|
1230
|
+
}
|
|
1231
|
+
turns.push({ query: q, answer: a, turnNumber: turns.length + 1 });
|
|
1232
|
+
}
|
|
1233
|
+
i++;
|
|
1234
|
+
}
|
|
1235
|
+
return turns;
|
|
1236
|
+
}
|
|
1237
|
+
async getLastConversationId(notebookId) {
|
|
1238
|
+
const params = [[], null, notebookId, 1];
|
|
1239
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_LAST_CONVERSATION_ID, params, {
|
|
1240
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1241
|
+
allowNull: true
|
|
1242
|
+
});
|
|
1243
|
+
if (!Array.isArray(result)) return null;
|
|
1244
|
+
for (const group of result) {
|
|
1245
|
+
if (!Array.isArray(group)) continue;
|
|
1246
|
+
for (const conv of group) {
|
|
1247
|
+
if (Array.isArray(conv) && typeof conv[0] === "string") {
|
|
1248
|
+
return conv[0];
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return null;
|
|
1253
|
+
}
|
|
1254
|
+
clearCache(conversationId) {
|
|
1255
|
+
if (conversationId) {
|
|
1256
|
+
this.conversationCache.delete(conversationId);
|
|
1257
|
+
} else {
|
|
1258
|
+
this.conversationCache.clear();
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
_buildHistory(conversationId) {
|
|
1262
|
+
const turns = this.conversationCache.get(conversationId) ?? [];
|
|
1263
|
+
if (!turns.length) return null;
|
|
1264
|
+
const history = [];
|
|
1265
|
+
for (const turn of turns) {
|
|
1266
|
+
history.push([turn.answer, null, 2]);
|
|
1267
|
+
history.push([turn.query, null, 1]);
|
|
1268
|
+
}
|
|
1269
|
+
return history;
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
function parseStreamingResponse(rawText) {
|
|
1273
|
+
let text = rawText;
|
|
1274
|
+
if (text.startsWith(")]}'")) text = text.slice(4);
|
|
1275
|
+
const lines = text.trim().split("\n");
|
|
1276
|
+
let bestMarkedAnswer = "";
|
|
1277
|
+
let bestUnmarkedAnswer = "";
|
|
1278
|
+
let serverConvId = null;
|
|
1279
|
+
const references = [];
|
|
1280
|
+
function processChunk(jsonStr) {
|
|
1281
|
+
let data;
|
|
1282
|
+
try {
|
|
1283
|
+
data = JSON.parse(jsonStr);
|
|
1284
|
+
} catch {
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
if (!Array.isArray(data)) return;
|
|
1288
|
+
for (const item of data) {
|
|
1289
|
+
if (!Array.isArray(item) || item.length < 3 || item[0] !== "wrb.fr") continue;
|
|
1290
|
+
const innerJson = item[2];
|
|
1291
|
+
if (typeof innerJson !== "string") continue;
|
|
1292
|
+
let innerData;
|
|
1293
|
+
try {
|
|
1294
|
+
innerData = JSON.parse(innerJson);
|
|
1295
|
+
} catch {
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1298
|
+
if (!Array.isArray(innerData) || !innerData.length) continue;
|
|
1299
|
+
const first = innerData[0];
|
|
1300
|
+
if (!Array.isArray(first) || !first.length) continue;
|
|
1301
|
+
const answerText = first[0];
|
|
1302
|
+
if (typeof answerText !== "string" || !answerText) continue;
|
|
1303
|
+
const typeInfo = first[4];
|
|
1304
|
+
const isAnswer = Array.isArray(typeInfo) && typeInfo.length > 0 && typeInfo[typeInfo.length - 1] === 1;
|
|
1305
|
+
const convData = first[2];
|
|
1306
|
+
if (!serverConvId && Array.isArray(convData) && convData.length > 0 && typeof convData[0] === "string") {
|
|
1307
|
+
serverConvId = convData[0];
|
|
1308
|
+
}
|
|
1309
|
+
if (Array.isArray(typeInfo) && typeInfo.length > 3) {
|
|
1310
|
+
const citations = typeInfo[3];
|
|
1311
|
+
if (Array.isArray(citations)) {
|
|
1312
|
+
for (const cite of citations) {
|
|
1313
|
+
const sourceId = extractUuid(cite);
|
|
1314
|
+
if (sourceId) {
|
|
1315
|
+
references.push({ sourceId, title: null, url: null });
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
if (isAnswer && answerText.length > bestMarkedAnswer.length) {
|
|
1321
|
+
bestMarkedAnswer = answerText;
|
|
1322
|
+
} else if (!isAnswer && answerText.length > bestUnmarkedAnswer.length) {
|
|
1323
|
+
bestUnmarkedAnswer = answerText;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
let i = 0;
|
|
1328
|
+
while (i < lines.length) {
|
|
1329
|
+
const line = (lines[i] ?? "").trim();
|
|
1330
|
+
if (!line) {
|
|
1331
|
+
i++;
|
|
1332
|
+
continue;
|
|
1333
|
+
}
|
|
1334
|
+
if (/^\d+$/.test(line)) {
|
|
1335
|
+
i++;
|
|
1336
|
+
const next = lines[i];
|
|
1337
|
+
if (next !== void 0) processChunk(next);
|
|
1338
|
+
i++;
|
|
1339
|
+
} else {
|
|
1340
|
+
processChunk(line);
|
|
1341
|
+
i++;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
return {
|
|
1345
|
+
answer: bestMarkedAnswer || bestUnmarkedAnswer,
|
|
1346
|
+
conversationId: serverConvId,
|
|
1347
|
+
references
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
function extractUuid(data, depth = 8) {
|
|
1351
|
+
if (depth <= 0 || data == null) return null;
|
|
1352
|
+
if (typeof data === "string") return UUID_RE.test(data) ? data : null;
|
|
1353
|
+
if (Array.isArray(data)) {
|
|
1354
|
+
for (const item of data) {
|
|
1355
|
+
const found = extractUuid(item, depth - 1);
|
|
1356
|
+
if (found) return found;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
return null;
|
|
1360
|
+
}
|
|
1361
|
+
function randomUUID() {
|
|
1362
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
1363
|
+
return crypto.randomUUID();
|
|
1364
|
+
}
|
|
1365
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
1366
|
+
const r = Math.random() * 16 | 0;
|
|
1367
|
+
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// src/api/notebooks.ts
|
|
1372
|
+
init_enums();
|
|
1373
|
+
var NotebooksAPI = class {
|
|
1374
|
+
constructor(rpc) {
|
|
1375
|
+
this.rpc = rpc;
|
|
1376
|
+
}
|
|
1377
|
+
async list() {
|
|
1378
|
+
const params = [null, 1, null, [2]];
|
|
1379
|
+
const result = await this.rpc.call(exports.RPCMethod.LIST_NOTEBOOKS, params);
|
|
1380
|
+
if (!Array.isArray(result) || !result.length) return [];
|
|
1381
|
+
const raw = Array.isArray(result[0]) ? result[0] : result;
|
|
1382
|
+
return raw.map((nb) => parseNotebook(nb));
|
|
1383
|
+
}
|
|
1384
|
+
async create(title) {
|
|
1385
|
+
const params = [title, null, null, [2], [1]];
|
|
1386
|
+
const result = await this.rpc.call(exports.RPCMethod.CREATE_NOTEBOOK, params);
|
|
1387
|
+
return parseNotebook(result);
|
|
1388
|
+
}
|
|
1389
|
+
async get(notebookId) {
|
|
1390
|
+
const params = [notebookId, null, [2], null, 0];
|
|
1391
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_NOTEBOOK, params, {
|
|
1392
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1393
|
+
});
|
|
1394
|
+
const data = Array.isArray(result) && result.length ? result[0] : result;
|
|
1395
|
+
return parseNotebook(data);
|
|
1396
|
+
}
|
|
1397
|
+
async delete(notebookId) {
|
|
1398
|
+
const params = [[notebookId], [2]];
|
|
1399
|
+
await this.rpc.call(exports.RPCMethod.DELETE_NOTEBOOK, params);
|
|
1400
|
+
return true;
|
|
1401
|
+
}
|
|
1402
|
+
async rename(notebookId, newTitle) {
|
|
1403
|
+
const params = [notebookId, [[null, null, null, [null, newTitle]]]];
|
|
1404
|
+
await this.rpc.call(exports.RPCMethod.RENAME_NOTEBOOK, params, {
|
|
1405
|
+
sourcePath: "/",
|
|
1406
|
+
allowNull: true
|
|
1407
|
+
});
|
|
1408
|
+
return this.get(notebookId);
|
|
1409
|
+
}
|
|
1410
|
+
async getSummary(notebookId) {
|
|
1411
|
+
const params = [notebookId, [2]];
|
|
1412
|
+
const result = await this.rpc.call(exports.RPCMethod.SUMMARIZE, params, {
|
|
1413
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1414
|
+
});
|
|
1415
|
+
try {
|
|
1416
|
+
if (Array.isArray(result)) {
|
|
1417
|
+
const val = result[0]?.[0]?.[0];
|
|
1418
|
+
return typeof val === "string" ? val : "";
|
|
1419
|
+
}
|
|
1420
|
+
} catch {
|
|
1421
|
+
}
|
|
1422
|
+
return "";
|
|
1423
|
+
}
|
|
1424
|
+
async getDescription(notebookId) {
|
|
1425
|
+
const params = [notebookId, [2]];
|
|
1426
|
+
const result = await this.rpc.call(exports.RPCMethod.SUMMARIZE, params, {
|
|
1427
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1428
|
+
});
|
|
1429
|
+
let summary = "";
|
|
1430
|
+
const suggestedTopics = [];
|
|
1431
|
+
try {
|
|
1432
|
+
if (Array.isArray(result)) {
|
|
1433
|
+
const outer = result[0];
|
|
1434
|
+
if (Array.isArray(outer)) {
|
|
1435
|
+
const summaryVal = outer[0]?.[0];
|
|
1436
|
+
if (typeof summaryVal === "string") summary = summaryVal;
|
|
1437
|
+
const topicsList = outer[1]?.[0];
|
|
1438
|
+
if (Array.isArray(topicsList)) {
|
|
1439
|
+
for (const t of topicsList) {
|
|
1440
|
+
const question = typeof t[0] === "string" ? t[0] : "";
|
|
1441
|
+
const prompt = typeof t[1] === "string" ? t[1] : "";
|
|
1442
|
+
suggestedTopics.push({ question, prompt });
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
} catch {
|
|
1448
|
+
}
|
|
1449
|
+
return { summary, suggestedTopics };
|
|
1758
1450
|
}
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1451
|
+
};
|
|
1452
|
+
|
|
1453
|
+
// src/api/notes.ts
|
|
1454
|
+
init_enums();
|
|
1455
|
+
var NotesAPI = class {
|
|
1456
|
+
constructor(rpc) {
|
|
1457
|
+
this.rpc = rpc;
|
|
1458
|
+
}
|
|
1459
|
+
async list(notebookId) {
|
|
1460
|
+
const params = [notebookId, [2]];
|
|
1461
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_NOTES_AND_MIND_MAPS, params, {
|
|
1462
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1764
1463
|
});
|
|
1765
|
-
|
|
1766
|
-
const
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1464
|
+
const notes = [];
|
|
1465
|
+
const mindMaps = [];
|
|
1466
|
+
if (!Array.isArray(result)) return { notes, mindMaps };
|
|
1467
|
+
try {
|
|
1468
|
+
const notesData = result[0];
|
|
1469
|
+
if (Array.isArray(notesData)) {
|
|
1470
|
+
for (const n of notesData) {
|
|
1471
|
+
if (Array.isArray(n)) notes.push(parseNote(n));
|
|
1472
|
+
}
|
|
1774
1473
|
}
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1474
|
+
const mapsData = result[1];
|
|
1475
|
+
if (Array.isArray(mapsData)) {
|
|
1476
|
+
for (const m of mapsData) {
|
|
1477
|
+
if (Array.isArray(m)) {
|
|
1478
|
+
mindMaps.push({
|
|
1479
|
+
id: typeof m[0] === "string" ? m[0] : "",
|
|
1480
|
+
title: typeof m[2] === "string" ? m[2] : null,
|
|
1481
|
+
content: typeof m[1] === "string" ? m[1] : "",
|
|
1482
|
+
createdAt: Array.isArray(m[3]) && typeof m[3][0] === "number" ? new Date(m[3][0] * 1e3) : null
|
|
1483
|
+
});
|
|
1783
1484
|
}
|
|
1784
|
-
i++;
|
|
1785
1485
|
}
|
|
1786
|
-
turns.push({ query: q, answer: a, turnNumber: turns.length + 1 });
|
|
1787
1486
|
}
|
|
1788
|
-
|
|
1487
|
+
} catch {
|
|
1789
1488
|
}
|
|
1790
|
-
return
|
|
1489
|
+
return { notes, mindMaps };
|
|
1791
1490
|
}
|
|
1792
|
-
async
|
|
1793
|
-
const params = [
|
|
1794
|
-
const result = await this.rpc.call(exports.RPCMethod.
|
|
1491
|
+
async create(notebookId, content, title) {
|
|
1492
|
+
const params = [notebookId, content, title ?? null, [2]];
|
|
1493
|
+
const result = await this.rpc.call(exports.RPCMethod.CREATE_NOTE, params, {
|
|
1494
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1495
|
+
});
|
|
1496
|
+
if (Array.isArray(result)) return parseNote(result);
|
|
1497
|
+
throw new Error("Could not parse note creation response");
|
|
1498
|
+
}
|
|
1499
|
+
async update(notebookId, noteId, content, title) {
|
|
1500
|
+
const params = [notebookId, noteId, content, title ?? null, [2]];
|
|
1501
|
+
const result = await this.rpc.call(exports.RPCMethod.UPDATE_NOTE, params, {
|
|
1502
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1503
|
+
});
|
|
1504
|
+
if (Array.isArray(result)) return parseNote(result);
|
|
1505
|
+
return { id: noteId, title: title ?? null, content, createdAt: null, updatedAt: /* @__PURE__ */ new Date() };
|
|
1506
|
+
}
|
|
1507
|
+
async delete(notebookId, noteId) {
|
|
1508
|
+
const params = [notebookId, noteId, [2]];
|
|
1509
|
+
await this.rpc.call(exports.RPCMethod.DELETE_NOTE, params, {
|
|
1795
1510
|
sourcePath: `/notebook/${notebookId}`,
|
|
1796
1511
|
allowNull: true
|
|
1797
1512
|
});
|
|
1798
|
-
|
|
1799
|
-
for (const group of result) {
|
|
1800
|
-
if (!Array.isArray(group)) continue;
|
|
1801
|
-
for (const conv of group) {
|
|
1802
|
-
if (Array.isArray(conv) && typeof conv[0] === "string") {
|
|
1803
|
-
return conv[0];
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
return null;
|
|
1513
|
+
return true;
|
|
1808
1514
|
}
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1515
|
+
};
|
|
1516
|
+
|
|
1517
|
+
// src/api/research.ts
|
|
1518
|
+
init_enums();
|
|
1519
|
+
var ResearchAPI = class {
|
|
1520
|
+
constructor(rpc) {
|
|
1521
|
+
this.rpc = rpc;
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Start a research session.
|
|
1525
|
+
* @param source "web" or "drive"
|
|
1526
|
+
* @param mode "fast" or "deep" (deep only available for web)
|
|
1527
|
+
*/
|
|
1528
|
+
async start(notebookId, query, source = "web", mode = "fast") {
|
|
1529
|
+
if (mode === "deep" && source === "drive") {
|
|
1530
|
+
throw new Error("Deep research only supports web sources.");
|
|
1531
|
+
}
|
|
1532
|
+
const sourceType = source === "web" ? 1 : 2;
|
|
1533
|
+
let rpcId;
|
|
1534
|
+
let params;
|
|
1535
|
+
if (mode === "fast") {
|
|
1536
|
+
rpcId = exports.RPCMethod.START_FAST_RESEARCH;
|
|
1537
|
+
params = [[query, sourceType], null, 1, notebookId];
|
|
1812
1538
|
} else {
|
|
1813
|
-
|
|
1539
|
+
rpcId = exports.RPCMethod.START_DEEP_RESEARCH;
|
|
1540
|
+
params = [null, [1], [query, sourceType], 5, notebookId];
|
|
1814
1541
|
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1542
|
+
const result = await this.rpc.call(rpcId, params, {
|
|
1543
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1544
|
+
allowNull: true
|
|
1545
|
+
});
|
|
1546
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
1547
|
+
return {
|
|
1548
|
+
taskId: result[0],
|
|
1549
|
+
reportId: result.length > 1 ? result[1] : null,
|
|
1550
|
+
notebookId,
|
|
1551
|
+
query,
|
|
1552
|
+
mode
|
|
1553
|
+
};
|
|
1823
1554
|
}
|
|
1824
|
-
return
|
|
1555
|
+
return null;
|
|
1825
1556
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
function processChunk(jsonStr) {
|
|
1836
|
-
let data;
|
|
1837
|
-
try {
|
|
1838
|
-
data = JSON.parse(jsonStr);
|
|
1839
|
-
} catch {
|
|
1840
|
-
return;
|
|
1557
|
+
/** Poll for current research results in a notebook. */
|
|
1558
|
+
async poll(notebookId) {
|
|
1559
|
+
const params = [null, null, notebookId];
|
|
1560
|
+
let result = await this.rpc.call(exports.RPCMethod.POLL_RESEARCH, params, {
|
|
1561
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1562
|
+
allowNull: true
|
|
1563
|
+
});
|
|
1564
|
+
if (!Array.isArray(result) || !result.length) {
|
|
1565
|
+
return emptyResult();
|
|
1841
1566
|
}
|
|
1842
|
-
if (
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
const
|
|
1855
|
-
|
|
1856
|
-
const
|
|
1857
|
-
|
|
1858
|
-
const
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1567
|
+
if (Array.isArray(result[0]) && Array.isArray(result[0][0])) {
|
|
1568
|
+
result = result[0];
|
|
1569
|
+
}
|
|
1570
|
+
const parsedTasks = [];
|
|
1571
|
+
for (const taskData of result) {
|
|
1572
|
+
if (!Array.isArray(taskData) || taskData.length < 2) continue;
|
|
1573
|
+
const taskId = taskData[0];
|
|
1574
|
+
const taskInfo = taskData[1];
|
|
1575
|
+
if (typeof taskId !== "string" || !Array.isArray(taskInfo)) continue;
|
|
1576
|
+
const queryText = Array.isArray(taskInfo[1]) ? taskInfo[1][0] ?? "" : "";
|
|
1577
|
+
const sourcesAndSummary = Array.isArray(taskInfo[3]) ? taskInfo[3] : [];
|
|
1578
|
+
const statusCode = typeof taskInfo[4] === "number" ? taskInfo[4] : null;
|
|
1579
|
+
const sourcesData = Array.isArray(sourcesAndSummary[0]) ? sourcesAndSummary[0] : [];
|
|
1580
|
+
const summary = typeof sourcesAndSummary[1] === "string" ? sourcesAndSummary[1] : "";
|
|
1581
|
+
const parsedSources = [];
|
|
1582
|
+
let report = "";
|
|
1583
|
+
for (const src of sourcesData) {
|
|
1584
|
+
if (!Array.isArray(src) || src.length < 2) continue;
|
|
1585
|
+
let url = "";
|
|
1586
|
+
let title = "";
|
|
1587
|
+
let sourceReport = "";
|
|
1588
|
+
let resultType = parseResultType(src.length > 3 ? src[3] : 1);
|
|
1589
|
+
if (src[0] === null) {
|
|
1590
|
+
if (Array.isArray(src[1]) && src[1].length >= 2 && typeof src[1][0] === "string" && typeof src[1][1] === "string") {
|
|
1591
|
+
title = src[1][0];
|
|
1592
|
+
sourceReport = src[1][1];
|
|
1593
|
+
if (resultType === 1) resultType = 5;
|
|
1594
|
+
} else if (typeof src[1] === "string") {
|
|
1595
|
+
title = src[1];
|
|
1596
|
+
if (resultType === 1) resultType = 5;
|
|
1597
|
+
}
|
|
1598
|
+
} else {
|
|
1599
|
+
url = typeof src[0] === "string" ? src[0] : "";
|
|
1600
|
+
title = src.length > 1 && typeof src[1] === "string" ? src[1] : "";
|
|
1601
|
+
}
|
|
1602
|
+
if (title || url) {
|
|
1603
|
+
const parsed = { url, title, resultType, researchTaskId: taskId };
|
|
1604
|
+
if (sourceReport) parsed.reportMarkdown = sourceReport;
|
|
1605
|
+
parsedSources.push(parsed);
|
|
1606
|
+
if (!report && sourceReport) {
|
|
1607
|
+
report = sourceReport;
|
|
1608
|
+
} else if (!report) {
|
|
1609
|
+
const legacyReport = extractLegacyReport(src);
|
|
1610
|
+
if (legacyReport) {
|
|
1611
|
+
report = legacyReport;
|
|
1612
|
+
parsed.reportMarkdown = legacyReport;
|
|
1871
1613
|
}
|
|
1872
1614
|
}
|
|
1873
1615
|
}
|
|
1874
1616
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1617
|
+
const status = statusCode === 2 || statusCode === 6 ? "completed" : "in_progress";
|
|
1618
|
+
parsedTasks.push({
|
|
1619
|
+
taskId,
|
|
1620
|
+
status,
|
|
1621
|
+
query: queryText,
|
|
1622
|
+
sources: parsedSources,
|
|
1623
|
+
summary,
|
|
1624
|
+
report,
|
|
1625
|
+
tasks: []
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
if (parsedTasks.length > 0) {
|
|
1629
|
+
return { ...parsedTasks[0], tasks: parsedTasks };
|
|
1880
1630
|
}
|
|
1631
|
+
return emptyResult();
|
|
1881
1632
|
}
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1633
|
+
/**
|
|
1634
|
+
* Import selected research sources into the notebook.
|
|
1635
|
+
* Pass sources from poll() — web sources need `url`, deep research report entries
|
|
1636
|
+
* need `reportMarkdown` (resultType=5).
|
|
1637
|
+
*
|
|
1638
|
+
* Note: The API may return fewer items than imported. Use sources.list() to verify.
|
|
1639
|
+
*/
|
|
1640
|
+
async importSources(notebookId, taskId, sources) {
|
|
1641
|
+
if (!sources.length) return [];
|
|
1642
|
+
const taskIds = new Set(sources.map((s) => s.researchTaskId).filter(Boolean));
|
|
1643
|
+
if (taskIds.size > 1)
|
|
1644
|
+
throw new Error("Cannot import sources from multiple research tasks in one batch.");
|
|
1645
|
+
const effectiveTaskId = taskIds.size === 1 ? [...taskIds][0] : taskId;
|
|
1646
|
+
const reportSources = sources.filter((s) => s.resultType === 5 && s.title && s.reportMarkdown);
|
|
1647
|
+
const reportSourceSet = new Set(reportSources);
|
|
1648
|
+
const webSources = sources.filter((s) => s.url && !reportSourceSet.has(s));
|
|
1649
|
+
if (!webSources.length && !reportSources.length) return [];
|
|
1650
|
+
const sourceArray = [
|
|
1651
|
+
...reportSources.map((s) => buildReportEntry(s.title, s.reportMarkdown)),
|
|
1652
|
+
...webSources.map((s) => buildWebEntry(s.url, s.title))
|
|
1653
|
+
];
|
|
1654
|
+
const params = [null, [1], effectiveTaskId, notebookId, sourceArray];
|
|
1655
|
+
let result = await this.rpc.call(exports.RPCMethod.IMPORT_RESEARCH, params, {
|
|
1656
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1657
|
+
allowNull: true
|
|
1658
|
+
});
|
|
1659
|
+
if (!Array.isArray(result)) return [];
|
|
1660
|
+
if (result.length > 0 && Array.isArray(result[0]) && Array.isArray(result[0][0])) {
|
|
1661
|
+
result = result[0];
|
|
1888
1662
|
}
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
processChunk(line);
|
|
1896
|
-
i++;
|
|
1663
|
+
const imported = [];
|
|
1664
|
+
for (const srcData of result) {
|
|
1665
|
+
if (!Array.isArray(srcData) || srcData.length < 2) continue;
|
|
1666
|
+
const first = srcData[0];
|
|
1667
|
+
const srcId = Array.isArray(first) && first.length > 0 ? first[0] : null;
|
|
1668
|
+
if (srcId) imported.push({ id: srcId, title: srcData[1] });
|
|
1897
1669
|
}
|
|
1670
|
+
return imported;
|
|
1898
1671
|
}
|
|
1672
|
+
};
|
|
1673
|
+
function parseResultType(value) {
|
|
1674
|
+
if (typeof value === "number") return value;
|
|
1675
|
+
if (typeof value === "string") {
|
|
1676
|
+
const aliases = { web: 1, drive: 2, report: 5 };
|
|
1677
|
+
return aliases[value.toLowerCase()] ?? 1;
|
|
1678
|
+
}
|
|
1679
|
+
return 1;
|
|
1680
|
+
}
|
|
1681
|
+
function extractLegacyReport(src) {
|
|
1682
|
+
if (src.length <= 6 || !Array.isArray(src[6])) return "";
|
|
1683
|
+
return src[6].filter((c) => typeof c === "string" && !!c).join("\n\n");
|
|
1684
|
+
}
|
|
1685
|
+
function buildReportEntry(title, markdown) {
|
|
1686
|
+
return [null, [title, markdown], null, 3, null, null, null, null, null, null, 3];
|
|
1687
|
+
}
|
|
1688
|
+
function buildWebEntry(url, title) {
|
|
1689
|
+
return [null, null, [url, title], null, null, null, null, null, null, null, 2];
|
|
1690
|
+
}
|
|
1691
|
+
function emptyResult() {
|
|
1899
1692
|
return {
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1693
|
+
taskId: null,
|
|
1694
|
+
status: "no_research",
|
|
1695
|
+
query: "",
|
|
1696
|
+
sources: [],
|
|
1697
|
+
summary: "",
|
|
1698
|
+
report: "",
|
|
1699
|
+
tasks: []
|
|
1903
1700
|
};
|
|
1904
1701
|
}
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
if (found) return found;
|
|
1912
|
-
}
|
|
1702
|
+
|
|
1703
|
+
// src/api/settings.ts
|
|
1704
|
+
init_enums();
|
|
1705
|
+
var SettingsAPI = class {
|
|
1706
|
+
constructor(rpc) {
|
|
1707
|
+
this.rpc = rpc;
|
|
1913
1708
|
}
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1709
|
+
/** Get the current output language setting (e.g. "en", "ja", "zh_Hans"). */
|
|
1710
|
+
async getOutputLanguage() {
|
|
1711
|
+
const params = [null, [1, null, null, null, null, null, null, null, null, null, [1]]];
|
|
1712
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_USER_SETTINGS, params, {
|
|
1713
|
+
sourcePath: "/",
|
|
1714
|
+
allowNull: true
|
|
1715
|
+
});
|
|
1716
|
+
return extractNested(result, [0, 2, 4, 0]);
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
* Set the output language for artifact generation.
|
|
1720
|
+
* Pass a BCP-47 language code, e.g. "en", "ja", "zh_Hans".
|
|
1721
|
+
* Returns the language that was set, or null if the response couldn't be parsed.
|
|
1722
|
+
*/
|
|
1723
|
+
async setOutputLanguage(language) {
|
|
1724
|
+
if (!language) return null;
|
|
1725
|
+
const params = [[[null, [[null, null, null, null, [language]]]]]];
|
|
1726
|
+
const result = await this.rpc.call(exports.RPCMethod.SET_USER_SETTINGS, params, {
|
|
1727
|
+
sourcePath: "/",
|
|
1728
|
+
allowNull: true
|
|
1729
|
+
});
|
|
1730
|
+
return extractNested(result, [2, 4, 0]);
|
|
1731
|
+
}
|
|
1732
|
+
};
|
|
1733
|
+
function extractNested(data, path) {
|
|
1734
|
+
try {
|
|
1735
|
+
let cur = data;
|
|
1736
|
+
for (const idx of path) {
|
|
1737
|
+
if (!Array.isArray(cur)) return null;
|
|
1738
|
+
cur = cur[idx];
|
|
1739
|
+
}
|
|
1740
|
+
return typeof cur === "string" && cur ? cur : null;
|
|
1741
|
+
} catch {
|
|
1742
|
+
return null;
|
|
1919
1743
|
}
|
|
1920
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
1921
|
-
const r = Math.random() * 16 | 0;
|
|
1922
|
-
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
1923
|
-
});
|
|
1924
1744
|
}
|
|
1925
1745
|
|
|
1926
|
-
// src/api/
|
|
1746
|
+
// src/api/sharing.ts
|
|
1927
1747
|
init_enums();
|
|
1928
|
-
var
|
|
1748
|
+
var SharingAPI = class {
|
|
1929
1749
|
constructor(rpc) {
|
|
1930
1750
|
this.rpc = rpc;
|
|
1931
1751
|
}
|
|
1932
|
-
|
|
1752
|
+
/** Get current sharing configuration for a notebook. */
|
|
1753
|
+
async getStatus(notebookId) {
|
|
1933
1754
|
const params = [notebookId, [2]];
|
|
1934
|
-
const result = await this.rpc.call(exports.RPCMethod.
|
|
1935
|
-
sourcePath: `/notebook/${notebookId}
|
|
1755
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_SHARE_STATUS, params, {
|
|
1756
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1757
|
+
allowNull: true
|
|
1936
1758
|
});
|
|
1937
|
-
|
|
1938
|
-
const mindMaps = [];
|
|
1939
|
-
if (!Array.isArray(result)) return { notes, mindMaps };
|
|
1940
|
-
try {
|
|
1941
|
-
const notesData = result[0];
|
|
1942
|
-
if (Array.isArray(notesData)) {
|
|
1943
|
-
for (const n of notesData) {
|
|
1944
|
-
if (Array.isArray(n)) notes.push(parseNote(n));
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
const mapsData = result[1];
|
|
1948
|
-
if (Array.isArray(mapsData)) {
|
|
1949
|
-
for (const m of mapsData) {
|
|
1950
|
-
if (Array.isArray(m)) {
|
|
1951
|
-
mindMaps.push({
|
|
1952
|
-
id: typeof m[0] === "string" ? m[0] : "",
|
|
1953
|
-
title: typeof m[2] === "string" ? m[2] : null,
|
|
1954
|
-
content: typeof m[1] === "string" ? m[1] : "",
|
|
1955
|
-
createdAt: Array.isArray(m[3]) && typeof m[3][0] === "number" ? new Date(m[3][0] * 1e3) : null
|
|
1956
|
-
});
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
} catch {
|
|
1961
|
-
}
|
|
1962
|
-
return { notes, mindMaps };
|
|
1759
|
+
return parseShareStatus(result, notebookId);
|
|
1963
1760
|
}
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
const
|
|
1967
|
-
|
|
1761
|
+
/** Enable or disable public link sharing. Returns updated status. */
|
|
1762
|
+
async setPublic(notebookId, isPublic) {
|
|
1763
|
+
const access = isPublic ? exports.ShareAccess.ANYONE_WITH_LINK : exports.ShareAccess.RESTRICTED;
|
|
1764
|
+
const params = [[[notebookId, null, [access], [access, ""]]], 1, null, [2]];
|
|
1765
|
+
await this.rpc.call(exports.RPCMethod.SHARE_NOTEBOOK, params, {
|
|
1766
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1767
|
+
allowNull: true
|
|
1968
1768
|
});
|
|
1969
|
-
|
|
1970
|
-
throw new Error("Could not parse note creation response");
|
|
1769
|
+
return this.getStatus(notebookId);
|
|
1971
1770
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1771
|
+
/**
|
|
1772
|
+
* Set what viewers can access: full notebook or chat only.
|
|
1773
|
+
* Note: GET_SHARE_STATUS doesn't return view_level, so it's inferred from what was set.
|
|
1774
|
+
*/
|
|
1775
|
+
async setViewLevel(notebookId, level) {
|
|
1776
|
+
const params = [notebookId, [[null, null, null, null, null, null, null, null, [[level]]]]];
|
|
1777
|
+
await this.rpc.call(exports.RPCMethod.RENAME_NOTEBOOK, params, {
|
|
1778
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1779
|
+
allowNull: true
|
|
1976
1780
|
});
|
|
1977
|
-
|
|
1978
|
-
return {
|
|
1781
|
+
const status = await this.getStatus(notebookId);
|
|
1782
|
+
return { ...status, viewLevel: level };
|
|
1783
|
+
}
|
|
1784
|
+
/** Share notebook with a user. Returns updated status. */
|
|
1785
|
+
async addUser(notebookId, email, permission = exports.SharePermission.VIEWER, opts = {}) {
|
|
1786
|
+
if (permission === exports.SharePermission.OWNER) throw new Error("Cannot assign OWNER permission");
|
|
1787
|
+
if (permission === exports.SharePermission._REMOVE) throw new Error("Use removeUser() instead");
|
|
1788
|
+
const { notify = true, welcomeMessage = "" } = opts;
|
|
1789
|
+
const messageFlag = welcomeMessage ? 0 : 1;
|
|
1790
|
+
const notifyFlag = notify ? 1 : 0;
|
|
1791
|
+
const params = [
|
|
1792
|
+
[[notebookId, [[email, null, permission]], null, [messageFlag, welcomeMessage]]],
|
|
1793
|
+
notifyFlag,
|
|
1794
|
+
null,
|
|
1795
|
+
[2]
|
|
1796
|
+
];
|
|
1797
|
+
await this.rpc.call(exports.RPCMethod.SHARE_NOTEBOOK, params, {
|
|
1798
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1799
|
+
allowNull: true
|
|
1800
|
+
});
|
|
1801
|
+
return this.getStatus(notebookId);
|
|
1979
1802
|
}
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1803
|
+
/** Update an existing user's permission level. Returns updated status. */
|
|
1804
|
+
async updateUser(notebookId, email, permission) {
|
|
1805
|
+
return this.addUser(notebookId, email, permission, { notify: false });
|
|
1806
|
+
}
|
|
1807
|
+
/** Remove a user's access to the notebook. Returns updated status. */
|
|
1808
|
+
async removeUser(notebookId, email) {
|
|
1809
|
+
const params = [
|
|
1810
|
+
[[notebookId, [[email, null, exports.SharePermission._REMOVE]], null, [0, ""]]],
|
|
1811
|
+
0,
|
|
1812
|
+
null,
|
|
1813
|
+
[2]
|
|
1814
|
+
];
|
|
1815
|
+
await this.rpc.call(exports.RPCMethod.SHARE_NOTEBOOK, params, {
|
|
1983
1816
|
sourcePath: `/notebook/${notebookId}`,
|
|
1984
1817
|
allowNull: true
|
|
1985
1818
|
});
|
|
1986
|
-
return
|
|
1819
|
+
return this.getStatus(notebookId);
|
|
1987
1820
|
}
|
|
1988
1821
|
};
|
|
1822
|
+
var PERM_MAP = {
|
|
1823
|
+
1: "owner",
|
|
1824
|
+
2: "editor",
|
|
1825
|
+
3: "viewer"
|
|
1826
|
+
};
|
|
1827
|
+
function parseSharedUser(data) {
|
|
1828
|
+
const email = typeof data[0] === "string" ? data[0] : "";
|
|
1829
|
+
const permCode = typeof data[1] === "number" ? data[1] : 3;
|
|
1830
|
+
const permission = PERM_MAP[permCode] ?? "viewer";
|
|
1831
|
+
let displayName = null;
|
|
1832
|
+
let avatarUrl = null;
|
|
1833
|
+
if (Array.isArray(data[3])) {
|
|
1834
|
+
const info = data[3];
|
|
1835
|
+
displayName = typeof info[0] === "string" ? info[0] : null;
|
|
1836
|
+
avatarUrl = typeof info[1] === "string" ? info[1] : null;
|
|
1837
|
+
}
|
|
1838
|
+
return { email, permission, displayName, avatarUrl };
|
|
1839
|
+
}
|
|
1840
|
+
function parseShareStatus(data, notebookId) {
|
|
1841
|
+
const users = [];
|
|
1842
|
+
if (Array.isArray(data[0])) {
|
|
1843
|
+
for (const entry of data[0]) {
|
|
1844
|
+
if (Array.isArray(entry)) users.push(parseSharedUser(entry));
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
const isPublic = Array.isArray(data[1]) && data[1][0] === true;
|
|
1848
|
+
const access = isPublic ? exports.ShareAccess.ANYONE_WITH_LINK : exports.ShareAccess.RESTRICTED;
|
|
1849
|
+
const shareUrl = isPublic ? `https://notebooklm.google.com/notebook/${notebookId}` : null;
|
|
1850
|
+
return {
|
|
1851
|
+
notebookId,
|
|
1852
|
+
isPublic,
|
|
1853
|
+
access,
|
|
1854
|
+
viewLevel: exports.ShareViewLevel.FULL_NOTEBOOK,
|
|
1855
|
+
sharedUsers: users,
|
|
1856
|
+
shareUrl
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1989
1859
|
|
|
1990
|
-
// src/api/
|
|
1860
|
+
// src/api/sources.ts
|
|
1991
1861
|
init_enums();
|
|
1992
|
-
|
|
1993
|
-
|
|
1862
|
+
init_errors();
|
|
1863
|
+
var UPLOAD_URL = "https://notebooklm.google.com/upload/_/";
|
|
1864
|
+
var SourcesAPI = class {
|
|
1865
|
+
constructor(rpc, auth) {
|
|
1994
1866
|
this.rpc = rpc;
|
|
1867
|
+
this.auth = auth;
|
|
1995
1868
|
}
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
1869
|
+
async list(notebookId) {
|
|
1870
|
+
const params = [notebookId, null, [2], null, 0];
|
|
1871
|
+
const notebook = await this.rpc.call(exports.RPCMethod.GET_NOTEBOOK, params, {
|
|
1872
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1873
|
+
});
|
|
1874
|
+
if (!Array.isArray(notebook) || !notebook.length) return [];
|
|
1875
|
+
const nbInfo = notebook[0];
|
|
1876
|
+
if (!Array.isArray(nbInfo) || nbInfo.length <= 1) return [];
|
|
1877
|
+
const sourcesList = nbInfo[1];
|
|
1878
|
+
if (!Array.isArray(sourcesList)) return [];
|
|
1879
|
+
return sourcesList.filter((s) => Array.isArray(s) && s.length > 0).map((s) => parseSource(s));
|
|
1880
|
+
}
|
|
1881
|
+
async get(notebookId, sourceId) {
|
|
1882
|
+
const sources = await this.list(notebookId);
|
|
1883
|
+
return sources.find((s) => s.id === sourceId) ?? null;
|
|
1884
|
+
}
|
|
1885
|
+
async addUrl(notebookId, url, opts = {}) {
|
|
1886
|
+
const isYouTube = url.includes("youtube.com") || url.includes("youtu.be");
|
|
2007
1887
|
let params;
|
|
2008
|
-
if (
|
|
2009
|
-
|
|
2010
|
-
|
|
1888
|
+
if (isYouTube) {
|
|
1889
|
+
params = [
|
|
1890
|
+
[[null, null, null, null, null, null, null, [url], null, null, 1]],
|
|
1891
|
+
notebookId,
|
|
1892
|
+
[2],
|
|
1893
|
+
[1, null, null, null, null, null, null, null, null, null, [1]]
|
|
1894
|
+
];
|
|
2011
1895
|
} else {
|
|
2012
|
-
|
|
2013
|
-
params = [null, [1], [query, sourceType], 5, notebookId];
|
|
1896
|
+
params = [[[null, null, [url], null, null, null, null, null]], notebookId, [2], null, null];
|
|
2014
1897
|
}
|
|
2015
|
-
const result = await this.rpc.call(
|
|
1898
|
+
const result = await this.rpc.call(exports.RPCMethod.ADD_SOURCE, params, {
|
|
2016
1899
|
sourcePath: `/notebook/${notebookId}`,
|
|
2017
|
-
allowNull:
|
|
1900
|
+
allowNull: isYouTube
|
|
2018
1901
|
});
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
reportId: result.length > 1 ? result[1] : null,
|
|
2023
|
-
notebookId,
|
|
2024
|
-
query,
|
|
2025
|
-
mode
|
|
2026
|
-
};
|
|
1902
|
+
const sourceId = extractSourceId(result);
|
|
1903
|
+
if (opts.waitUntilReady) {
|
|
1904
|
+
return this.waitUntilReady(notebookId, sourceId, opts.waitTimeout);
|
|
2027
1905
|
}
|
|
2028
|
-
return
|
|
1906
|
+
return {
|
|
1907
|
+
id: sourceId,
|
|
1908
|
+
title: url,
|
|
1909
|
+
url,
|
|
1910
|
+
kind: "web_page",
|
|
1911
|
+
createdAt: null,
|
|
1912
|
+
status: "processing",
|
|
1913
|
+
_typeCode: null
|
|
1914
|
+
};
|
|
2029
1915
|
}
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
1916
|
+
async addText(notebookId, text, title, opts = {}) {
|
|
1917
|
+
const params = [
|
|
1918
|
+
[[null, [title ?? "", text], null, null, null, null, null, null]],
|
|
1919
|
+
notebookId,
|
|
1920
|
+
[2],
|
|
1921
|
+
null,
|
|
1922
|
+
null
|
|
1923
|
+
];
|
|
1924
|
+
const result = await this.rpc.call(exports.RPCMethod.ADD_SOURCE, params, {
|
|
1925
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1926
|
+
});
|
|
1927
|
+
const sourceId = extractSourceId(result);
|
|
1928
|
+
if (opts.waitUntilReady) {
|
|
1929
|
+
return this.waitUntilReady(notebookId, sourceId, opts.waitTimeout);
|
|
1930
|
+
}
|
|
1931
|
+
return {
|
|
1932
|
+
id: sourceId,
|
|
1933
|
+
title: title ?? null,
|
|
1934
|
+
url: null,
|
|
1935
|
+
kind: "pasted_text",
|
|
1936
|
+
createdAt: null,
|
|
1937
|
+
status: "processing",
|
|
1938
|
+
_typeCode: null
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1941
|
+
async addFile(notebookId, filePath, mimeType, opts = {}) {
|
|
1942
|
+
const fileData = fs.readFileSync(filePath);
|
|
1943
|
+
const fileName = filePath.split("/").pop() ?? "file";
|
|
1944
|
+
return this.addFileBuffer(notebookId, fileData, fileName, mimeType, opts);
|
|
1945
|
+
}
|
|
1946
|
+
async addFileBuffer(notebookId, data, fileName, _mimeType, opts = {}) {
|
|
1947
|
+
const params = [
|
|
1948
|
+
[[fileName]],
|
|
1949
|
+
notebookId,
|
|
1950
|
+
[2],
|
|
1951
|
+
[1, null, null, null, null, null, null, null, null, null, [1]]
|
|
1952
|
+
];
|
|
1953
|
+
const result = await this.rpc.call(exports.RPCMethod.ADD_SOURCE_FILE, params, {
|
|
2034
1954
|
sourcePath: `/notebook/${notebookId}`,
|
|
2035
1955
|
allowNull: true
|
|
2036
1956
|
});
|
|
2037
|
-
|
|
2038
|
-
|
|
1957
|
+
const sourceId = extractSourceId(result);
|
|
1958
|
+
const uploadUrl = await this.startResumableUpload(notebookId, fileName, data.length, sourceId);
|
|
1959
|
+
await this.uploadFile(uploadUrl, data);
|
|
1960
|
+
if (opts.waitUntilReady) {
|
|
1961
|
+
return this.waitUntilReady(notebookId, sourceId, opts.waitTimeout);
|
|
2039
1962
|
}
|
|
2040
|
-
|
|
2041
|
-
|
|
1963
|
+
return {
|
|
1964
|
+
id: sourceId,
|
|
1965
|
+
title: fileName,
|
|
1966
|
+
url: null,
|
|
1967
|
+
kind: "pdf",
|
|
1968
|
+
// Defaults to generic kind until ready
|
|
1969
|
+
createdAt: null,
|
|
1970
|
+
status: "processing",
|
|
1971
|
+
_typeCode: null
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
async startResumableUpload(notebookId, fileName, fileSize, sourceId) {
|
|
1975
|
+
const startResp = await fetch(`${UPLOAD_URL}?authuser=0`, {
|
|
1976
|
+
method: "POST",
|
|
1977
|
+
headers: {
|
|
1978
|
+
Accept: "*/*",
|
|
1979
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
1980
|
+
Cookie: this.auth.cookieHeader,
|
|
1981
|
+
Origin: "https://notebooklm.google.com",
|
|
1982
|
+
Referer: "https://notebooklm.google.com/",
|
|
1983
|
+
"x-goog-authuser": "0",
|
|
1984
|
+
"x-goog-upload-command": "start",
|
|
1985
|
+
"x-goog-upload-header-content-length": String(fileSize),
|
|
1986
|
+
"x-goog-upload-protocol": "resumable"
|
|
1987
|
+
},
|
|
1988
|
+
body: JSON.stringify({
|
|
1989
|
+
PROJECT_ID: notebookId,
|
|
1990
|
+
SOURCE_NAME: fileName,
|
|
1991
|
+
SOURCE_ID: sourceId
|
|
1992
|
+
})
|
|
1993
|
+
});
|
|
1994
|
+
if (!startResp.ok) {
|
|
1995
|
+
throw new Error(`Upload initiation failed: HTTP ${startResp.status}`);
|
|
2042
1996
|
}
|
|
2043
|
-
const
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
const taskId = taskData[0];
|
|
2047
|
-
const taskInfo = taskData[1];
|
|
2048
|
-
if (typeof taskId !== "string" || !Array.isArray(taskInfo)) continue;
|
|
2049
|
-
const queryText = Array.isArray(taskInfo[1]) ? taskInfo[1][0] ?? "" : "";
|
|
2050
|
-
const sourcesAndSummary = Array.isArray(taskInfo[3]) ? taskInfo[3] : [];
|
|
2051
|
-
const statusCode = typeof taskInfo[4] === "number" ? taskInfo[4] : null;
|
|
2052
|
-
const sourcesData = Array.isArray(sourcesAndSummary[0]) ? sourcesAndSummary[0] : [];
|
|
2053
|
-
const summary = typeof sourcesAndSummary[1] === "string" ? sourcesAndSummary[1] : "";
|
|
2054
|
-
const parsedSources = [];
|
|
2055
|
-
let report = "";
|
|
2056
|
-
for (const src of sourcesData) {
|
|
2057
|
-
if (!Array.isArray(src) || src.length < 2) continue;
|
|
2058
|
-
let url = "";
|
|
2059
|
-
let title = "";
|
|
2060
|
-
let sourceReport = "";
|
|
2061
|
-
let resultType = parseResultType(src.length > 3 ? src[3] : 1);
|
|
2062
|
-
if (src[0] === null) {
|
|
2063
|
-
if (Array.isArray(src[1]) && src[1].length >= 2 && typeof src[1][0] === "string" && typeof src[1][1] === "string") {
|
|
2064
|
-
title = src[1][0];
|
|
2065
|
-
sourceReport = src[1][1];
|
|
2066
|
-
if (resultType === 1) resultType = 5;
|
|
2067
|
-
} else if (typeof src[1] === "string") {
|
|
2068
|
-
title = src[1];
|
|
2069
|
-
if (resultType === 1) resultType = 5;
|
|
2070
|
-
}
|
|
2071
|
-
} else {
|
|
2072
|
-
url = typeof src[0] === "string" ? src[0] : "";
|
|
2073
|
-
title = src.length > 1 && typeof src[1] === "string" ? src[1] : "";
|
|
2074
|
-
}
|
|
2075
|
-
if (title || url) {
|
|
2076
|
-
const parsed = { url, title, resultType, researchTaskId: taskId };
|
|
2077
|
-
if (sourceReport) parsed.reportMarkdown = sourceReport;
|
|
2078
|
-
parsedSources.push(parsed);
|
|
2079
|
-
if (!report && sourceReport) {
|
|
2080
|
-
report = sourceReport;
|
|
2081
|
-
} else if (!report) {
|
|
2082
|
-
const legacyReport = extractLegacyReport(src);
|
|
2083
|
-
if (legacyReport) {
|
|
2084
|
-
report = legacyReport;
|
|
2085
|
-
parsed.reportMarkdown = legacyReport;
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
}
|
|
2089
|
-
}
|
|
2090
|
-
const status = statusCode === 2 || statusCode === 6 ? "completed" : "in_progress";
|
|
2091
|
-
parsedTasks.push({
|
|
2092
|
-
taskId,
|
|
2093
|
-
status,
|
|
2094
|
-
query: queryText,
|
|
2095
|
-
sources: parsedSources,
|
|
2096
|
-
summary,
|
|
2097
|
-
report,
|
|
2098
|
-
tasks: []
|
|
2099
|
-
});
|
|
1997
|
+
const uploadSessionUrl = startResp.headers.get("x-goog-upload-url");
|
|
1998
|
+
if (!uploadSessionUrl) {
|
|
1999
|
+
throw new Error("Failed to get upload URL from response headers");
|
|
2100
2000
|
}
|
|
2101
|
-
|
|
2102
|
-
|
|
2001
|
+
return uploadSessionUrl;
|
|
2002
|
+
}
|
|
2003
|
+
async uploadFile(uploadUrl, data) {
|
|
2004
|
+
const uploadResp = await fetch(uploadUrl, {
|
|
2005
|
+
method: "POST",
|
|
2006
|
+
headers: {
|
|
2007
|
+
Accept: "*/*",
|
|
2008
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
|
|
2009
|
+
Cookie: this.auth.cookieHeader,
|
|
2010
|
+
Origin: "https://notebooklm.google.com",
|
|
2011
|
+
Referer: "https://notebooklm.google.com/",
|
|
2012
|
+
"X-Goog-Upload-Command": "upload, finalize",
|
|
2013
|
+
"X-Goog-Upload-Offset": "0"
|
|
2014
|
+
},
|
|
2015
|
+
body: new Uint8Array(data)
|
|
2016
|
+
});
|
|
2017
|
+
if (!uploadResp.ok) {
|
|
2018
|
+
throw new Error(`File upload failed: HTTP ${uploadResp.status}`);
|
|
2103
2019
|
}
|
|
2104
|
-
|
|
2020
|
+
const uploadResult = await uploadResp.text();
|
|
2021
|
+
return uploadResult.trim();
|
|
2022
|
+
}
|
|
2023
|
+
async delete(notebookId, sourceId) {
|
|
2024
|
+
const params = [notebookId, [sourceId], [2]];
|
|
2025
|
+
await this.rpc.call(exports.RPCMethod.DELETE_SOURCE, params, {
|
|
2026
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
2027
|
+
allowNull: true
|
|
2028
|
+
});
|
|
2029
|
+
return true;
|
|
2105
2030
|
}
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
* need `reportMarkdown` (resultType=5).
|
|
2110
|
-
*
|
|
2111
|
-
* Note: The API may return fewer items than imported. Use sources.list() to verify.
|
|
2112
|
-
*/
|
|
2113
|
-
async importSources(notebookId, taskId, sources) {
|
|
2114
|
-
if (!sources.length) return [];
|
|
2115
|
-
const taskIds = new Set(sources.map((s) => s.researchTaskId).filter(Boolean));
|
|
2116
|
-
if (taskIds.size > 1)
|
|
2117
|
-
throw new Error("Cannot import sources from multiple research tasks in one batch.");
|
|
2118
|
-
const effectiveTaskId = taskIds.size === 1 ? [...taskIds][0] : taskId;
|
|
2119
|
-
const reportSources = sources.filter((s) => s.resultType === 5 && s.title && s.reportMarkdown);
|
|
2120
|
-
const reportSourceSet = new Set(reportSources);
|
|
2121
|
-
const webSources = sources.filter((s) => s.url && !reportSourceSet.has(s));
|
|
2122
|
-
if (!webSources.length && !reportSources.length) return [];
|
|
2123
|
-
const sourceArray = [
|
|
2124
|
-
...reportSources.map((s) => buildReportEntry(s.title, s.reportMarkdown)),
|
|
2125
|
-
...webSources.map((s) => buildWebEntry(s.url, s.title))
|
|
2126
|
-
];
|
|
2127
|
-
const params = [null, [1], effectiveTaskId, notebookId, sourceArray];
|
|
2128
|
-
let result = await this.rpc.call(exports.RPCMethod.IMPORT_RESEARCH, params, {
|
|
2031
|
+
async refresh(notebookId, sourceId) {
|
|
2032
|
+
const params = [notebookId, sourceId, [2]];
|
|
2033
|
+
await this.rpc.call(exports.RPCMethod.REFRESH_SOURCE, params, {
|
|
2129
2034
|
sourcePath: `/notebook/${notebookId}`,
|
|
2130
2035
|
allowNull: true
|
|
2131
2036
|
});
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
const
|
|
2140
|
-
|
|
2141
|
-
|
|
2037
|
+
return true;
|
|
2038
|
+
}
|
|
2039
|
+
async waitUntilReady(notebookId, sourceId, timeout = 120, initialInterval = 1, maxInterval = 10, backoffFactor = 1.5) {
|
|
2040
|
+
const deadline = Date.now() + timeout * 1e3;
|
|
2041
|
+
let interval = initialInterval;
|
|
2042
|
+
let lastStatus;
|
|
2043
|
+
while (Date.now() < deadline) {
|
|
2044
|
+
const source = await this.get(notebookId, sourceId);
|
|
2045
|
+
if (source) {
|
|
2046
|
+
if (source.status === "ready") return source;
|
|
2047
|
+
if (source.status === "error") {
|
|
2048
|
+
throw new exports.SourceProcessingError(sourceId, 3);
|
|
2049
|
+
}
|
|
2050
|
+
lastStatus = source._typeCode ?? void 0;
|
|
2051
|
+
}
|
|
2052
|
+
await sleep2(interval * 1e3);
|
|
2053
|
+
interval = Math.min(interval * backoffFactor, maxInterval);
|
|
2142
2054
|
}
|
|
2143
|
-
|
|
2055
|
+
throw new exports.SourceTimeoutError(sourceId, timeout, lastStatus);
|
|
2144
2056
|
}
|
|
2145
2057
|
};
|
|
2146
|
-
function
|
|
2147
|
-
if (
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2058
|
+
function extractSourceId(result) {
|
|
2059
|
+
if (Array.isArray(result)) {
|
|
2060
|
+
let current = result;
|
|
2061
|
+
while (Array.isArray(current) && current.length > 0) {
|
|
2062
|
+
if (typeof current[0] === "string") {
|
|
2063
|
+
if (current[0].length > 8) {
|
|
2064
|
+
return current[0];
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
current = current[0];
|
|
2068
|
+
}
|
|
2069
|
+
for (const item of result) {
|
|
2070
|
+
if (typeof item === "string" && item.length > 8) return item;
|
|
2071
|
+
}
|
|
2151
2072
|
}
|
|
2152
|
-
return
|
|
2073
|
+
if (typeof result === "string") return result;
|
|
2074
|
+
console.log("extractSourceId debug info: could not parse:", JSON.stringify(result, null, 2));
|
|
2075
|
+
throw new Error("Could not extract source ID from API response");
|
|
2153
2076
|
}
|
|
2154
|
-
function
|
|
2155
|
-
|
|
2156
|
-
return src[6].filter((c) => typeof c === "string" && !!c).join("\n\n");
|
|
2077
|
+
function sleep2(ms) {
|
|
2078
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2157
2079
|
}
|
|
2158
|
-
|
|
2159
|
-
|
|
2080
|
+
|
|
2081
|
+
// src/index.ts
|
|
2082
|
+
init_auth();
|
|
2083
|
+
|
|
2084
|
+
// src/client.ts
|
|
2085
|
+
init_auth();
|
|
2086
|
+
|
|
2087
|
+
// src/rpc/core.ts
|
|
2088
|
+
init_errors();
|
|
2089
|
+
|
|
2090
|
+
// src/rpc/decoder.ts
|
|
2091
|
+
init_errors();
|
|
2092
|
+
function stripAntiXSSI(response) {
|
|
2093
|
+
if (response.startsWith(")]}'")) {
|
|
2094
|
+
const match = /\)\]\}'\r?\n/.exec(response);
|
|
2095
|
+
if (match) return response.slice(match[0].length);
|
|
2096
|
+
}
|
|
2097
|
+
return response;
|
|
2160
2098
|
}
|
|
2161
|
-
function
|
|
2162
|
-
|
|
2099
|
+
function parseChunkedResponse(response) {
|
|
2100
|
+
if (!response || !response.trim()) return [];
|
|
2101
|
+
const chunks = [];
|
|
2102
|
+
let skippedCount = 0;
|
|
2103
|
+
const lines = response.trim().split("\n");
|
|
2104
|
+
let i = 0;
|
|
2105
|
+
while (i < lines.length) {
|
|
2106
|
+
const line = (lines[i] ?? "").trim();
|
|
2107
|
+
if (!line) {
|
|
2108
|
+
i++;
|
|
2109
|
+
continue;
|
|
2110
|
+
}
|
|
2111
|
+
if (/^\d+$/.test(line)) {
|
|
2112
|
+
i++;
|
|
2113
|
+
if (i < lines.length) {
|
|
2114
|
+
try {
|
|
2115
|
+
const chunk = JSON.parse(lines[i] ?? "");
|
|
2116
|
+
chunks.push(chunk);
|
|
2117
|
+
} catch {
|
|
2118
|
+
skippedCount++;
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
i++;
|
|
2122
|
+
} else {
|
|
2123
|
+
try {
|
|
2124
|
+
const chunk = JSON.parse(line);
|
|
2125
|
+
chunks.push(chunk);
|
|
2126
|
+
} catch {
|
|
2127
|
+
skippedCount++;
|
|
2128
|
+
}
|
|
2129
|
+
i++;
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
if (skippedCount > 0 && lines.length > 0) {
|
|
2133
|
+
const errorRate = skippedCount / lines.length;
|
|
2134
|
+
if (errorRate > 0.1) {
|
|
2135
|
+
throw new exports.RPCError(
|
|
2136
|
+
`Response parsing failed: ${skippedCount} of ${lines.length} chunks malformed`,
|
|
2137
|
+
{ rawResponse: response.slice(0, 500) }
|
|
2138
|
+
);
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
return chunks;
|
|
2163
2142
|
}
|
|
2164
|
-
function
|
|
2165
|
-
return
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
report: "",
|
|
2172
|
-
tasks: []
|
|
2173
|
-
};
|
|
2143
|
+
function containsUserDisplayableError(obj) {
|
|
2144
|
+
if (typeof obj === "string") return obj.includes("UserDisplayableError");
|
|
2145
|
+
if (Array.isArray(obj)) return obj.some(containsUserDisplayableError);
|
|
2146
|
+
if (obj !== null && typeof obj === "object") {
|
|
2147
|
+
return Object.values(obj).some(containsUserDisplayableError);
|
|
2148
|
+
}
|
|
2149
|
+
return false;
|
|
2174
2150
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2151
|
+
function collectRPCIds(chunks) {
|
|
2152
|
+
const ids = [];
|
|
2153
|
+
for (const chunk of chunks) {
|
|
2154
|
+
if (!Array.isArray(chunk)) continue;
|
|
2155
|
+
const items = Array.isArray(chunk[0]) ? chunk : [chunk];
|
|
2156
|
+
for (const item of items) {
|
|
2157
|
+
if (!Array.isArray(item) || item.length < 2) continue;
|
|
2158
|
+
if ((item[0] === "wrb.fr" || item[0] === "er") && typeof item[1] === "string") {
|
|
2159
|
+
ids.push(item[1]);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2181
2162
|
}
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2163
|
+
return ids;
|
|
2164
|
+
}
|
|
2165
|
+
function extractRPCResult(chunks, rpcId) {
|
|
2166
|
+
for (const chunk of chunks) {
|
|
2167
|
+
if (!Array.isArray(chunk)) continue;
|
|
2168
|
+
const items = Array.isArray(chunk[0]) ? chunk : [chunk];
|
|
2169
|
+
for (const item of items) {
|
|
2170
|
+
if (!Array.isArray(item) || item.length < 3) continue;
|
|
2171
|
+
if (item[0] === "er" && item[1] === rpcId) {
|
|
2172
|
+
const code = item[2];
|
|
2173
|
+
let msg = "Unknown error";
|
|
2174
|
+
if (typeof code === "number") {
|
|
2175
|
+
if (code === 429) msg = "API rate limit exceeded. Please wait before retrying.";
|
|
2176
|
+
else if (code === 401 || code === 403) msg = "Authentication required or forbidden.";
|
|
2177
|
+
else if (code === 404) msg = "Resource not found.";
|
|
2178
|
+
else if (code >= 500) msg = `Server error ${code}. Try again later.`;
|
|
2179
|
+
else msg = `Error code: ${code}`;
|
|
2180
|
+
} else if (typeof code === "string") {
|
|
2181
|
+
msg = code;
|
|
2182
|
+
}
|
|
2183
|
+
throw new exports.RPCError(msg, { methodId: rpcId, rpcCode: code });
|
|
2184
|
+
}
|
|
2185
|
+
if (item[0] === "wrb.fr" && item[1] === rpcId) {
|
|
2186
|
+
const resultData = item[2];
|
|
2187
|
+
if (resultData === null && item.length > 5 && item[5] != null) {
|
|
2188
|
+
if (containsUserDisplayableError(item[5])) {
|
|
2189
|
+
throw new exports.RateLimitError(
|
|
2190
|
+
"API rate limit or quota exceeded. Please wait before retrying.",
|
|
2191
|
+
{ methodId: rpcId, rpcCode: "USER_DISPLAYABLE_ERROR" }
|
|
2192
|
+
);
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
if (typeof resultData === "string") {
|
|
2196
|
+
try {
|
|
2197
|
+
return JSON.parse(resultData);
|
|
2198
|
+
} catch {
|
|
2199
|
+
return resultData;
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
if (resultData === null) {
|
|
2203
|
+
console.log(
|
|
2204
|
+
"decodeResponse debug info: resultData is exactly null. Full item Array:",
|
|
2205
|
+
JSON.stringify(item)
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
return resultData;
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2190
2211
|
}
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2212
|
+
return void 0;
|
|
2213
|
+
}
|
|
2214
|
+
function decodeResponse(rawResponse, rpcId, allowNull = false) {
|
|
2215
|
+
const cleaned = stripAntiXSSI(rawResponse);
|
|
2216
|
+
const chunks = parseChunkedResponse(cleaned);
|
|
2217
|
+
const responsePreview = cleaned.slice(0, 500);
|
|
2218
|
+
const foundIds = collectRPCIds(chunks);
|
|
2219
|
+
let result;
|
|
2220
|
+
try {
|
|
2221
|
+
result = extractRPCResult(chunks, rpcId);
|
|
2222
|
+
} catch (e) {
|
|
2223
|
+
if (e instanceof exports.RPCError && e.foundIds.length === 0) {
|
|
2224
|
+
throw new exports.RPCError(e.message, {
|
|
2225
|
+
methodId: e.methodId,
|
|
2226
|
+
rpcCode: e.rpcCode,
|
|
2227
|
+
foundIds,
|
|
2228
|
+
rawResponse: responsePreview
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
throw e;
|
|
2204
2232
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
cur = cur[idx];
|
|
2233
|
+
if (result === void 0 && !allowNull) {
|
|
2234
|
+
if (foundIds.length > 0 && !foundIds.includes(rpcId)) {
|
|
2235
|
+
throw new exports.RPCError(
|
|
2236
|
+
`No result for RPC ID '${rpcId}'. Response has IDs: ${foundIds.join(", ")}. Method ID may have changed.`,
|
|
2237
|
+
{ methodId: rpcId, foundIds, rawResponse: responsePreview }
|
|
2238
|
+
);
|
|
2212
2239
|
}
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2240
|
+
throw new exports.RPCError(`No result found for RPC ID: ${rpcId} (${chunks.length} chunks parsed)`, {
|
|
2241
|
+
methodId: rpcId,
|
|
2242
|
+
foundIds,
|
|
2243
|
+
rawResponse: responsePreview
|
|
2244
|
+
});
|
|
2216
2245
|
}
|
|
2246
|
+
return result ?? null;
|
|
2217
2247
|
}
|
|
2218
2248
|
|
|
2219
|
-
// src/
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
async setViewLevel(notebookId, level) {
|
|
2249
|
-
const params = [notebookId, [[null, null, null, null, null, null, null, null, [[level]]]]];
|
|
2250
|
-
await this.rpc.call(exports.RPCMethod.RENAME_NOTEBOOK, params, {
|
|
2251
|
-
sourcePath: `/notebook/${notebookId}`,
|
|
2252
|
-
allowNull: true
|
|
2253
|
-
});
|
|
2254
|
-
const status = await this.getStatus(notebookId);
|
|
2255
|
-
return { ...status, viewLevel: level };
|
|
2256
|
-
}
|
|
2257
|
-
/** Share notebook with a user. Returns updated status. */
|
|
2258
|
-
async addUser(notebookId, email, permission = exports.SharePermission.VIEWER, opts = {}) {
|
|
2259
|
-
if (permission === exports.SharePermission.OWNER) throw new Error("Cannot assign OWNER permission");
|
|
2260
|
-
if (permission === exports.SharePermission._REMOVE) throw new Error("Use removeUser() instead");
|
|
2261
|
-
const { notify = true, welcomeMessage = "" } = opts;
|
|
2262
|
-
const messageFlag = welcomeMessage ? 0 : 1;
|
|
2263
|
-
const notifyFlag = notify ? 1 : 0;
|
|
2264
|
-
const params = [
|
|
2265
|
-
[[notebookId, [[email, null, permission]], null, [messageFlag, welcomeMessage]]],
|
|
2266
|
-
notifyFlag,
|
|
2267
|
-
null,
|
|
2268
|
-
[2]
|
|
2269
|
-
];
|
|
2270
|
-
await this.rpc.call(exports.RPCMethod.SHARE_NOTEBOOK, params, {
|
|
2271
|
-
sourcePath: `/notebook/${notebookId}`,
|
|
2272
|
-
allowNull: true
|
|
2273
|
-
});
|
|
2274
|
-
return this.getStatus(notebookId);
|
|
2249
|
+
// src/rpc/encoder.ts
|
|
2250
|
+
function encodeRPCRequest(methodId, params) {
|
|
2251
|
+
const paramsJson = JSON.stringify(params);
|
|
2252
|
+
return [[[methodId, paramsJson, null, "generic"]]];
|
|
2253
|
+
}
|
|
2254
|
+
function buildRequestBody(rpcRequest, csrfToken) {
|
|
2255
|
+
const fReq = encodeURIComponent(JSON.stringify(rpcRequest));
|
|
2256
|
+
const at = encodeURIComponent(csrfToken);
|
|
2257
|
+
return `f.req=${fReq}&at=${at}&`;
|
|
2258
|
+
}
|
|
2259
|
+
function buildUrlParams(methodId, sessionId, sourcePath = "/") {
|
|
2260
|
+
return new URLSearchParams({
|
|
2261
|
+
rpcids: methodId,
|
|
2262
|
+
"source-path": sourcePath,
|
|
2263
|
+
"f.sid": sessionId,
|
|
2264
|
+
hl: "en",
|
|
2265
|
+
rt: "c"
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
// src/rpc/core.ts
|
|
2270
|
+
var BATCHEXECUTE_URL = "https://notebooklm.google.com/_/LabsTailwindUi/data/batchexecute";
|
|
2271
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
2272
|
+
var RPCCore = class {
|
|
2273
|
+
auth;
|
|
2274
|
+
timeoutMs;
|
|
2275
|
+
constructor(auth, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
2276
|
+
this.auth = auth;
|
|
2277
|
+
this.timeoutMs = timeoutMs;
|
|
2275
2278
|
}
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
+
async call(methodId, params, opts = {}) {
|
|
2280
|
+
const sourcePath = opts.sourcePath ?? "/";
|
|
2281
|
+
const allowNull = opts.allowNull ?? false;
|
|
2282
|
+
const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
|
|
2283
|
+
const rpcRequest = encodeRPCRequest(methodId, params);
|
|
2284
|
+
const body = buildRequestBody(rpcRequest, this.auth.csrfToken);
|
|
2285
|
+
const urlParams = buildUrlParams(methodId, this.auth.sessionId, sourcePath);
|
|
2286
|
+
const url = `${BATCHEXECUTE_URL}?${urlParams.toString()}`;
|
|
2287
|
+
const controller = new AbortController();
|
|
2288
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2289
|
+
let response;
|
|
2290
|
+
try {
|
|
2291
|
+
response = await fetch(url, {
|
|
2292
|
+
method: "POST",
|
|
2293
|
+
headers: {
|
|
2294
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
2295
|
+
Cookie: this.auth.cookieHeader
|
|
2296
|
+
},
|
|
2297
|
+
body,
|
|
2298
|
+
signal: controller.signal
|
|
2299
|
+
});
|
|
2300
|
+
} catch (e) {
|
|
2301
|
+
clearTimeout(timer);
|
|
2302
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
2303
|
+
throw new exports.RPCTimeoutError(`Request timed out calling ${methodId}`, {
|
|
2304
|
+
methodId,
|
|
2305
|
+
originalError: e
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2308
|
+
throw new exports.NetworkError(`Request failed calling ${methodId}: ${String(e)}`, {
|
|
2309
|
+
methodId,
|
|
2310
|
+
originalError: e instanceof Error ? e : void 0
|
|
2311
|
+
});
|
|
2312
|
+
} finally {
|
|
2313
|
+
clearTimeout(timer);
|
|
2314
|
+
}
|
|
2315
|
+
if (!response.ok) {
|
|
2316
|
+
const status = response.status;
|
|
2317
|
+
if (status === 429) {
|
|
2318
|
+
const retryAfterHeader = response.headers.get("retry-after");
|
|
2319
|
+
const retryAfter = retryAfterHeader ? parseInt(retryAfterHeader, 10) : void 0;
|
|
2320
|
+
throw new exports.RateLimitError(`API rate limit exceeded calling ${methodId}`, {
|
|
2321
|
+
methodId,
|
|
2322
|
+
retryAfter: isNaN(retryAfter ?? NaN) ? void 0 : retryAfter
|
|
2323
|
+
});
|
|
2324
|
+
}
|
|
2325
|
+
if (status === 401 || status === 403) {
|
|
2326
|
+
throw new exports.AuthError(`HTTP ${status} calling ${methodId}: authentication required`, {
|
|
2327
|
+
methodId
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
if (status >= 500) {
|
|
2331
|
+
throw new exports.ServerError(`Server error ${status} calling ${methodId}`, {
|
|
2332
|
+
methodId,
|
|
2333
|
+
statusCode: status
|
|
2334
|
+
});
|
|
2335
|
+
}
|
|
2336
|
+
if (status >= 400) {
|
|
2337
|
+
throw new exports.ClientError(`Client error ${status} calling ${methodId}`, {
|
|
2338
|
+
methodId,
|
|
2339
|
+
statusCode: status
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2342
|
+
throw new exports.RPCError(`HTTP ${status} calling ${methodId}`, { methodId });
|
|
2343
|
+
}
|
|
2344
|
+
const text = await response.text();
|
|
2345
|
+
return decodeResponse(text, methodId, allowNull);
|
|
2279
2346
|
}
|
|
2280
|
-
/**
|
|
2281
|
-
async
|
|
2282
|
-
const params = [
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
[2]
|
|
2287
|
-
];
|
|
2288
|
-
await this.rpc.call(exports.RPCMethod.SHARE_NOTEBOOK, params, {
|
|
2289
|
-
sourcePath: `/notebook/${notebookId}`,
|
|
2290
|
-
allowNull: true
|
|
2347
|
+
/** Extract source IDs from a notebook (used by chat/artifact APIs). */
|
|
2348
|
+
async getSourceIds(notebookId) {
|
|
2349
|
+
const params = [notebookId, null, [2], null, 0];
|
|
2350
|
+
const { RPCMethod: RPCMethod2 } = await Promise.resolve().then(() => (init_enums(), enums_exports));
|
|
2351
|
+
const data = await this.call(RPCMethod2.GET_NOTEBOOK, params, {
|
|
2352
|
+
sourcePath: `/notebook/${notebookId}`
|
|
2291
2353
|
});
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
const info = data[3];
|
|
2308
|
-
displayName = typeof info[0] === "string" ? info[0] : null;
|
|
2309
|
-
avatarUrl = typeof info[1] === "string" ? info[1] : null;
|
|
2310
|
-
}
|
|
2311
|
-
return { email, permission, displayName, avatarUrl };
|
|
2312
|
-
}
|
|
2313
|
-
function parseShareStatus(data, notebookId) {
|
|
2314
|
-
const users = [];
|
|
2315
|
-
if (Array.isArray(data[0])) {
|
|
2316
|
-
for (const entry of data[0]) {
|
|
2317
|
-
if (Array.isArray(entry)) users.push(parseSharedUser(entry));
|
|
2354
|
+
const sourceIds = [];
|
|
2355
|
+
if (!Array.isArray(data) || !data.length) return sourceIds;
|
|
2356
|
+
try {
|
|
2357
|
+
const nbInfo = data[0];
|
|
2358
|
+
if (!Array.isArray(nbInfo) || nbInfo.length <= 1) return sourceIds;
|
|
2359
|
+
const sources = nbInfo[1];
|
|
2360
|
+
if (!Array.isArray(sources)) return sourceIds;
|
|
2361
|
+
for (const src of sources) {
|
|
2362
|
+
if (!Array.isArray(src) || !src.length) continue;
|
|
2363
|
+
const first = src[0];
|
|
2364
|
+
if (Array.isArray(first) && first.length > 0 && typeof first[0] === "string") {
|
|
2365
|
+
sourceIds.push(first[0]);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
} catch {
|
|
2318
2369
|
}
|
|
2370
|
+
return sourceIds;
|
|
2319
2371
|
}
|
|
2320
|
-
|
|
2321
|
-
const access = isPublic ? exports.ShareAccess.ANYONE_WITH_LINK : exports.ShareAccess.RESTRICTED;
|
|
2322
|
-
const shareUrl = isPublic ? `https://notebooklm.google.com/notebook/${notebookId}` : null;
|
|
2323
|
-
return {
|
|
2324
|
-
notebookId,
|
|
2325
|
-
isPublic,
|
|
2326
|
-
access,
|
|
2327
|
-
viewLevel: exports.ShareViewLevel.FULL_NOTEBOOK,
|
|
2328
|
-
sharedUsers: users,
|
|
2329
|
-
shareUrl
|
|
2330
|
-
};
|
|
2331
|
-
}
|
|
2372
|
+
};
|
|
2332
2373
|
|
|
2333
2374
|
// src/client.ts
|
|
2334
2375
|
var NotebookLMClient = class _NotebookLMClient {
|
|
@@ -2372,7 +2413,6 @@ var NotebookLMClient = class _NotebookLMClient {
|
|
|
2372
2413
|
};
|
|
2373
2414
|
|
|
2374
2415
|
// src/index.ts
|
|
2375
|
-
init_auth();
|
|
2376
2416
|
init_enums();
|
|
2377
2417
|
init_errors();
|
|
2378
2418
|
|