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