notebooklm-sdk 0.3.2 → 0.3.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 +23 -9
- package/dist/{auth-Dxsm8894.d.cts → auth-BlG6x47F.d.cts} +2 -1
- package/dist/{auth-Dxsm8894.d.ts → auth-BlG6x47F.d.ts} +2 -1
- package/dist/auth.cjs +7 -0
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +2 -2
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +7 -1
- package/dist/auth.js.map +1 -1
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +581 -402
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -7
- package/dist/index.d.ts +36 -7
- package/dist/index.js +535 -377
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -309,356 +309,176 @@ var init_enums = __esm({
|
|
|
309
309
|
}
|
|
310
310
|
});
|
|
311
311
|
|
|
312
|
+
// src/api/artifacts.ts
|
|
313
|
+
init_enums();
|
|
314
|
+
|
|
312
315
|
// src/types/errors.ts
|
|
313
|
-
var NotebookLMError
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
constructor(message) {
|
|
318
|
-
super(message);
|
|
319
|
-
this.name = this.constructor.name;
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
NetworkError = class extends NotebookLMError {
|
|
323
|
-
methodId;
|
|
324
|
-
originalError;
|
|
325
|
-
constructor(message, opts = {}) {
|
|
326
|
-
super(message);
|
|
327
|
-
this.methodId = opts.methodId;
|
|
328
|
-
this.originalError = opts.originalError;
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
RPCTimeoutError = class extends NetworkError {
|
|
332
|
-
};
|
|
333
|
-
RPCError = class extends NotebookLMError {
|
|
334
|
-
methodId;
|
|
335
|
-
rawResponse;
|
|
336
|
-
rpcCode;
|
|
337
|
-
foundIds;
|
|
338
|
-
constructor(message, opts = {}) {
|
|
339
|
-
super(message);
|
|
340
|
-
this.methodId = opts.methodId;
|
|
341
|
-
this.rawResponse = opts.rawResponse ? opts.rawResponse.slice(0, 500) : void 0;
|
|
342
|
-
this.rpcCode = opts.rpcCode;
|
|
343
|
-
this.foundIds = opts.foundIds ?? [];
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
AuthError = class extends RPCError {
|
|
347
|
-
};
|
|
348
|
-
RateLimitError = class extends RPCError {
|
|
349
|
-
retryAfter;
|
|
350
|
-
constructor(message, opts = {}) {
|
|
351
|
-
super(message, opts);
|
|
352
|
-
this.retryAfter = opts.retryAfter;
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
ServerError = class extends RPCError {
|
|
356
|
-
statusCode;
|
|
357
|
-
constructor(message, opts = {}) {
|
|
358
|
-
super(message, opts);
|
|
359
|
-
this.statusCode = opts.statusCode;
|
|
360
|
-
}
|
|
361
|
-
};
|
|
362
|
-
ClientError = class extends RPCError {
|
|
363
|
-
statusCode;
|
|
364
|
-
constructor(message, opts = {}) {
|
|
365
|
-
super(message, opts);
|
|
366
|
-
this.statusCode = opts.statusCode;
|
|
367
|
-
}
|
|
368
|
-
};
|
|
369
|
-
NotebookError = class extends NotebookLMError {
|
|
370
|
-
};
|
|
371
|
-
NotebookNotFoundError = class extends NotebookError {
|
|
372
|
-
notebookId;
|
|
373
|
-
constructor(notebookId) {
|
|
374
|
-
super(`Notebook not found: ${notebookId}`);
|
|
375
|
-
this.notebookId = notebookId;
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
SourceError = class extends NotebookLMError {
|
|
379
|
-
};
|
|
380
|
-
SourceNotFoundError = class extends SourceError {
|
|
381
|
-
sourceId;
|
|
382
|
-
constructor(sourceId) {
|
|
383
|
-
super(`Source not found: ${sourceId}`);
|
|
384
|
-
this.sourceId = sourceId;
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
SourceAddError = class extends SourceError {
|
|
388
|
-
url;
|
|
389
|
-
cause;
|
|
390
|
-
constructor(url, opts = {}) {
|
|
391
|
-
super(
|
|
392
|
-
opts.message ?? `Failed to add source: ${url}
|
|
393
|
-
Possible causes:
|
|
394
|
-
- URL is invalid or inaccessible
|
|
395
|
-
- Content is behind a paywall or requires authentication
|
|
396
|
-
- Rate limiting or quota exceeded`
|
|
397
|
-
);
|
|
398
|
-
this.url = url;
|
|
399
|
-
this.cause = opts.cause;
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
SourceProcessingError = class extends SourceError {
|
|
403
|
-
sourceId;
|
|
404
|
-
status;
|
|
405
|
-
constructor(sourceId, status = 3, message) {
|
|
406
|
-
super(message ?? `Source ${sourceId} failed to process`);
|
|
407
|
-
this.sourceId = sourceId;
|
|
408
|
-
this.status = status;
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
SourceTimeoutError = class extends SourceError {
|
|
412
|
-
sourceId;
|
|
413
|
-
timeout;
|
|
414
|
-
lastStatus;
|
|
415
|
-
constructor(sourceId, timeout, lastStatus) {
|
|
416
|
-
const statusInfo = lastStatus != null ? ` (last status: ${lastStatus})` : "";
|
|
417
|
-
super(`Source ${sourceId} not ready after ${timeout.toFixed(1)}s${statusInfo}`);
|
|
418
|
-
this.sourceId = sourceId;
|
|
419
|
-
this.timeout = timeout;
|
|
420
|
-
this.lastStatus = lastStatus;
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
ArtifactError = class extends NotebookLMError {
|
|
424
|
-
};
|
|
425
|
-
ArtifactNotFoundError = class extends ArtifactError {
|
|
426
|
-
artifactId;
|
|
427
|
-
artifactType;
|
|
428
|
-
constructor(artifactId, artifactType) {
|
|
429
|
-
const typeInfo = artifactType ? ` ${artifactType}` : "";
|
|
430
|
-
super(`${typeInfo.trim() || "Artifact"} ${artifactId} not found`);
|
|
431
|
-
this.artifactId = artifactId;
|
|
432
|
-
this.artifactType = artifactType;
|
|
433
|
-
}
|
|
434
|
-
};
|
|
435
|
-
ArtifactNotReadyError = class extends ArtifactError {
|
|
436
|
-
artifactType;
|
|
437
|
-
artifactId;
|
|
438
|
-
status;
|
|
439
|
-
constructor(artifactType, opts = {}) {
|
|
440
|
-
const base = opts.artifactId ? `${artifactType} artifact ${opts.artifactId} is not ready` : `No completed ${artifactType} found`;
|
|
441
|
-
const statusInfo = opts.status ? ` (status: ${opts.status})` : "";
|
|
442
|
-
super(`${base}${statusInfo}`);
|
|
443
|
-
this.artifactType = artifactType;
|
|
444
|
-
this.artifactId = opts.artifactId;
|
|
445
|
-
this.status = opts.status;
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
|
-
ArtifactParseError = class extends ArtifactError {
|
|
449
|
-
artifactType;
|
|
450
|
-
artifactId;
|
|
451
|
-
details;
|
|
452
|
-
cause;
|
|
453
|
-
constructor(artifactType, opts = {}) {
|
|
454
|
-
let msg = `Failed to parse ${artifactType} artifact`;
|
|
455
|
-
if (opts.artifactId) msg += ` ${opts.artifactId}`;
|
|
456
|
-
if (opts.details) msg += `: ${opts.details}`;
|
|
457
|
-
super(msg);
|
|
458
|
-
this.artifactType = artifactType;
|
|
459
|
-
this.artifactId = opts.artifactId;
|
|
460
|
-
this.details = opts.details;
|
|
461
|
-
this.cause = opts.cause;
|
|
462
|
-
}
|
|
463
|
-
};
|
|
464
|
-
ArtifactDownloadError = class extends ArtifactError {
|
|
465
|
-
artifactType;
|
|
466
|
-
artifactId;
|
|
467
|
-
details;
|
|
468
|
-
cause;
|
|
469
|
-
constructor(artifactType, opts = {}) {
|
|
470
|
-
let msg = `Failed to download ${artifactType} artifact`;
|
|
471
|
-
if (opts.artifactId) msg += ` ${opts.artifactId}`;
|
|
472
|
-
if (opts.details) msg += `: ${opts.details}`;
|
|
473
|
-
super(msg);
|
|
474
|
-
this.artifactType = artifactType;
|
|
475
|
-
this.artifactId = opts.artifactId;
|
|
476
|
-
this.details = opts.details;
|
|
477
|
-
this.cause = opts.cause;
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
ChatError = class extends NotebookLMError {
|
|
481
|
-
};
|
|
316
|
+
var NotebookLMError = class extends Error {
|
|
317
|
+
constructor(message) {
|
|
318
|
+
super(message);
|
|
319
|
+
this.name = this.constructor.name;
|
|
482
320
|
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
fetchTokens: () => fetchTokens,
|
|
492
|
-
loadCookiesFromFile: () => loadCookiesFromFile,
|
|
493
|
-
loadCookiesFromMap: () => loadCookiesFromMap,
|
|
494
|
-
loadCookiesFromObject: () => loadCookiesFromObject,
|
|
495
|
-
loadCookiesFromString: () => loadCookiesFromString
|
|
496
|
-
});
|
|
497
|
-
function loadCookiesFromFile(filePath) {
|
|
498
|
-
let raw;
|
|
499
|
-
try {
|
|
500
|
-
raw = readFileSync(filePath, "utf-8");
|
|
501
|
-
} catch {
|
|
502
|
-
throw new AuthError(`Session file not found: ${filePath}
|
|
503
|
-
Run: npx notebooklm-sdk login`);
|
|
321
|
+
};
|
|
322
|
+
var NetworkError = class extends NotebookLMError {
|
|
323
|
+
methodId;
|
|
324
|
+
originalError;
|
|
325
|
+
constructor(message, opts = {}) {
|
|
326
|
+
super(message);
|
|
327
|
+
this.methodId = opts.methodId;
|
|
328
|
+
this.originalError = opts.originalError;
|
|
504
329
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
330
|
+
};
|
|
331
|
+
var RPCTimeoutError = class extends NetworkError {
|
|
332
|
+
};
|
|
333
|
+
var RPCError = class extends NotebookLMError {
|
|
334
|
+
methodId;
|
|
335
|
+
rawResponse;
|
|
336
|
+
rpcCode;
|
|
337
|
+
foundIds;
|
|
338
|
+
constructor(message, opts = {}) {
|
|
339
|
+
super(message);
|
|
340
|
+
this.methodId = opts.methodId;
|
|
341
|
+
this.rawResponse = opts.rawResponse ? opts.rawResponse.slice(0, 500) : void 0;
|
|
342
|
+
this.rpcCode = opts.rpcCode;
|
|
343
|
+
this.foundIds = opts.foundIds ?? [];
|
|
516
344
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const idx = part.indexOf("=");
|
|
526
|
-
if (idx > 0) {
|
|
527
|
-
const name = part.slice(0, idx).trim();
|
|
528
|
-
const value = part.slice(idx + 1).trim();
|
|
529
|
-
if (name) map[name] = value;
|
|
530
|
-
}
|
|
345
|
+
};
|
|
346
|
+
var AuthError = class extends RPCError {
|
|
347
|
+
};
|
|
348
|
+
var RateLimitError = class extends RPCError {
|
|
349
|
+
retryAfter;
|
|
350
|
+
constructor(message, opts = {}) {
|
|
351
|
+
super(message, opts);
|
|
352
|
+
this.retryAfter = opts.retryAfter;
|
|
531
353
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
if (!isAllowedDomain(domain) || !name) continue;
|
|
539
|
-
const isBase = domain === ".google.com";
|
|
540
|
-
if (!(name in cookies) || isBase) {
|
|
541
|
-
cookies[name] = value;
|
|
542
|
-
}
|
|
354
|
+
};
|
|
355
|
+
var ServerError = class extends RPCError {
|
|
356
|
+
statusCode;
|
|
357
|
+
constructor(message, opts = {}) {
|
|
358
|
+
super(message, opts);
|
|
359
|
+
this.statusCode = opts.statusCode;
|
|
543
360
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
361
|
+
};
|
|
362
|
+
var ClientError = class extends RPCError {
|
|
363
|
+
statusCode;
|
|
364
|
+
constructor(message, opts = {}) {
|
|
365
|
+
super(message, opts);
|
|
366
|
+
this.statusCode = opts.statusCode;
|
|
548
367
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
368
|
+
};
|
|
369
|
+
var NotebookError = class extends NotebookLMError {
|
|
370
|
+
};
|
|
371
|
+
var NotebookNotFoundError = class extends NotebookError {
|
|
372
|
+
notebookId;
|
|
373
|
+
constructor(notebookId) {
|
|
374
|
+
super(`Notebook not found: ${notebookId}`);
|
|
375
|
+
this.notebookId = notebookId;
|
|
554
376
|
}
|
|
555
|
-
|
|
556
|
-
|
|
377
|
+
};
|
|
378
|
+
var SourceError = class extends NotebookLMError {
|
|
379
|
+
};
|
|
380
|
+
var SourceNotFoundError = class extends SourceError {
|
|
381
|
+
sourceId;
|
|
382
|
+
constructor(sourceId) {
|
|
383
|
+
super(`Source not found: ${sourceId}`);
|
|
384
|
+
this.sourceId = sourceId;
|
|
557
385
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
386
|
+
};
|
|
387
|
+
var SourceAddError = class extends SourceError {
|
|
388
|
+
url;
|
|
389
|
+
cause;
|
|
390
|
+
constructor(url, opts = {}) {
|
|
391
|
+
super(
|
|
392
|
+
opts.message ?? `Failed to add source: ${url}
|
|
393
|
+
Possible causes:
|
|
394
|
+
- URL is invalid or inaccessible
|
|
395
|
+
- Content is behind a paywall or requires authentication
|
|
396
|
+
- Rate limiting or quota exceeded`
|
|
397
|
+
);
|
|
398
|
+
this.url = url;
|
|
399
|
+
this.cause = opts.cause;
|
|
571
400
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
401
|
+
};
|
|
402
|
+
var SourceProcessingError = class extends SourceError {
|
|
403
|
+
sourceId;
|
|
404
|
+
status;
|
|
405
|
+
constructor(sourceId, status = 3, message) {
|
|
406
|
+
super(message ?? `Source ${sourceId} failed to process`);
|
|
407
|
+
this.sourceId = sourceId;
|
|
408
|
+
this.status = status;
|
|
575
409
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
throw new AuthError("CSRF token (SNlM0e) not found in NotebookLM page HTML.");
|
|
410
|
+
};
|
|
411
|
+
var SourceTimeoutError = class extends SourceError {
|
|
412
|
+
sourceId;
|
|
413
|
+
timeout;
|
|
414
|
+
lastStatus;
|
|
415
|
+
constructor(sourceId, timeout, lastStatus) {
|
|
416
|
+
const statusInfo = lastStatus != null ? ` (last status: ${lastStatus})` : "";
|
|
417
|
+
super(`Source ${sourceId} not ready after ${timeout.toFixed(1)}s${statusInfo}`);
|
|
418
|
+
this.sourceId = sourceId;
|
|
419
|
+
this.timeout = timeout;
|
|
420
|
+
this.lastStatus = lastStatus;
|
|
588
421
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}
|
|
597
|
-
|
|
422
|
+
};
|
|
423
|
+
var ArtifactError = class extends NotebookLMError {
|
|
424
|
+
};
|
|
425
|
+
var ArtifactNotFoundError = class extends ArtifactError {
|
|
426
|
+
artifactId;
|
|
427
|
+
artifactType;
|
|
428
|
+
constructor(artifactId, artifactType) {
|
|
429
|
+
const typeInfo = artifactType ? ` ${artifactType}` : "";
|
|
430
|
+
super(`${typeInfo.trim() || "Artifact"} ${artifactId} not found`);
|
|
431
|
+
this.artifactId = artifactId;
|
|
432
|
+
this.artifactType = artifactType;
|
|
598
433
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
} else if (opts.cookiesObject) {
|
|
612
|
-
if ("cookies" in opts.cookiesObject && Array.isArray(opts.cookiesObject.cookies)) {
|
|
613
|
-
const storageState = opts.cookiesObject;
|
|
614
|
-
cookieMap = loadCookiesFromObject(storageState);
|
|
615
|
-
googleCookieHeader = buildGoogleCookieHeader(storageState);
|
|
616
|
-
} else {
|
|
617
|
-
cookieMap = loadCookiesFromMap(opts.cookiesObject);
|
|
618
|
-
}
|
|
619
|
-
} else {
|
|
620
|
-
const envCookies = process.env["NOTEBOOKLM_COOKIES"];
|
|
621
|
-
const envFile = process.env["NOTEBOOKLM_COOKIES_FILE"];
|
|
622
|
-
if (envFile) {
|
|
623
|
-
cookieMap = loadCookiesFromFile(envFile);
|
|
624
|
-
} else if (existsSync(DEFAULT_SESSION_FILE)) {
|
|
625
|
-
const raw = readFileSync(DEFAULT_SESSION_FILE, "utf-8");
|
|
626
|
-
const storageState = JSON.parse(raw);
|
|
627
|
-
cookieMap = loadCookiesFromObject(storageState);
|
|
628
|
-
googleCookieHeader = buildGoogleCookieHeader(storageState);
|
|
629
|
-
} else if (existsSync("storage_state.json")) {
|
|
630
|
-
const raw = readFileSync("storage_state.json", "utf-8");
|
|
631
|
-
const storageState = JSON.parse(raw);
|
|
632
|
-
cookieMap = loadCookiesFromObject(storageState);
|
|
633
|
-
googleCookieHeader = buildGoogleCookieHeader(storageState);
|
|
634
|
-
} else if (envCookies) {
|
|
635
|
-
cookieMap = loadCookiesFromString(envCookies);
|
|
636
|
-
} else {
|
|
637
|
-
throw new AuthError("No session found. Run: npx notebooklm-sdk login");
|
|
638
|
-
}
|
|
434
|
+
};
|
|
435
|
+
var ArtifactNotReadyError = class extends ArtifactError {
|
|
436
|
+
artifactType;
|
|
437
|
+
artifactId;
|
|
438
|
+
status;
|
|
439
|
+
constructor(artifactType, opts = {}) {
|
|
440
|
+
const base = opts.artifactId ? `${artifactType} artifact ${opts.artifactId} is not ready` : `No completed ${artifactType} found`;
|
|
441
|
+
const statusInfo = opts.status ? ` (status: ${opts.status})` : "";
|
|
442
|
+
super(`${base}${statusInfo}`);
|
|
443
|
+
this.artifactType = artifactType;
|
|
444
|
+
this.artifactId = opts.artifactId;
|
|
445
|
+
this.status = opts.status;
|
|
639
446
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
NOTEBOOKLM_URL = "https://notebooklm.google.com/";
|
|
447
|
+
};
|
|
448
|
+
var ArtifactParseError = class extends ArtifactError {
|
|
449
|
+
artifactType;
|
|
450
|
+
artifactId;
|
|
451
|
+
details;
|
|
452
|
+
cause;
|
|
453
|
+
constructor(artifactType, opts = {}) {
|
|
454
|
+
let msg = `Failed to parse ${artifactType} artifact`;
|
|
455
|
+
if (opts.artifactId) msg += ` ${opts.artifactId}`;
|
|
456
|
+
if (opts.details) msg += `: ${opts.details}`;
|
|
457
|
+
super(msg);
|
|
458
|
+
this.artifactType = artifactType;
|
|
459
|
+
this.artifactId = opts.artifactId;
|
|
460
|
+
this.details = opts.details;
|
|
461
|
+
this.cause = opts.cause;
|
|
656
462
|
}
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
463
|
+
};
|
|
464
|
+
var ArtifactDownloadError = class extends ArtifactError {
|
|
465
|
+
artifactType;
|
|
466
|
+
artifactId;
|
|
467
|
+
details;
|
|
468
|
+
cause;
|
|
469
|
+
constructor(artifactType, opts = {}) {
|
|
470
|
+
let msg = `Failed to download ${artifactType} artifact`;
|
|
471
|
+
if (opts.artifactId) msg += ` ${opts.artifactId}`;
|
|
472
|
+
if (opts.details) msg += `: ${opts.details}`;
|
|
473
|
+
super(msg);
|
|
474
|
+
this.artifactType = artifactType;
|
|
475
|
+
this.artifactId = opts.artifactId;
|
|
476
|
+
this.details = opts.details;
|
|
477
|
+
this.cause = opts.cause;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
var ChatError = class extends NotebookLMError {
|
|
481
|
+
};
|
|
662
482
|
|
|
663
483
|
// src/types/models.ts
|
|
664
484
|
init_enums();
|
|
@@ -1118,17 +938,60 @@ ${opts.extraInstructions}` : cfg.prompt;
|
|
|
1118
938
|
// Polling / download
|
|
1119
939
|
// ---------------------------------------------------------------------------
|
|
1120
940
|
/** Poll until artifact reaches completed/failed status. */
|
|
1121
|
-
async waitUntilReady(notebookId, artifactId, timeout =
|
|
941
|
+
async waitUntilReady(notebookId, artifactId, timeout = 1800, pollInterval = 3) {
|
|
942
|
+
return this.pollUntilReady(notebookId, artifactId, {
|
|
943
|
+
timeoutSecs: timeout,
|
|
944
|
+
intervalSecs: pollInterval
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
/** Poll until artifact is fully ready, with optional progress hooks and cancellation. */
|
|
948
|
+
async pollUntilReady(notebookId, artifactId, opts = {}) {
|
|
949
|
+
const timeout = opts.timeoutSecs ?? 1800;
|
|
950
|
+
const pollInterval = opts.intervalSecs ?? 3;
|
|
1122
951
|
const deadline = Date.now() + timeout * 1e3;
|
|
952
|
+
let lastStatus = null;
|
|
1123
953
|
while (Date.now() < deadline) {
|
|
954
|
+
this.throwIfAborted(opts.signal);
|
|
955
|
+
const status = await this.pollStatus(notebookId, artifactId);
|
|
956
|
+
lastStatus = status;
|
|
957
|
+
if (opts.onTick) await opts.onTick(status);
|
|
1124
958
|
const artifact = await this.get(notebookId, artifactId);
|
|
1125
|
-
if (artifact?.status === "completed")
|
|
1126
|
-
|
|
1127
|
-
|
|
959
|
+
if (artifact?.status === "completed") {
|
|
960
|
+
if (artifact.kind === "audio" && !artifact.audioUrl || artifact.kind === "video" && !artifact.videoUrl) {
|
|
961
|
+
await sleep(pollInterval * 1e3);
|
|
962
|
+
continue;
|
|
963
|
+
}
|
|
964
|
+
return artifact;
|
|
965
|
+
}
|
|
966
|
+
if (artifact?.status === "failed" || status.status === "failed") {
|
|
967
|
+
throw new ArtifactNotReadyError(artifact?.kind ?? "artifact", {
|
|
968
|
+
artifactId,
|
|
969
|
+
status: "failed"
|
|
970
|
+
});
|
|
1128
971
|
}
|
|
1129
972
|
await sleep(pollInterval * 1e3);
|
|
1130
973
|
}
|
|
1131
|
-
throw new ArtifactNotReadyError("artifact", {
|
|
974
|
+
throw new ArtifactNotReadyError("artifact", {
|
|
975
|
+
artifactId,
|
|
976
|
+
status: lastStatus?.status ?? "timeout"
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
throwIfAborted(signal) {
|
|
980
|
+
if (!signal?.aborted) return;
|
|
981
|
+
throw new Error("Artifact polling aborted");
|
|
982
|
+
}
|
|
983
|
+
/** Get the current status of a generated artifact without waiting. */
|
|
984
|
+
async pollStatus(notebookId, artifactId) {
|
|
985
|
+
const rawList = await this._listRaw(notebookId);
|
|
986
|
+
for (const item of rawList) {
|
|
987
|
+
if (!Array.isArray(item) || item[0] !== artifactId) continue;
|
|
988
|
+
const statusCode = typeof item[4] === "number" ? item[4] : null;
|
|
989
|
+
return {
|
|
990
|
+
artifactId,
|
|
991
|
+
status: statusCode != null ? artifactStatusFromCode(statusCode) : "pending"
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
return { artifactId, status: "pending" };
|
|
1132
995
|
}
|
|
1133
996
|
/** Download audio content as a Buffer. */
|
|
1134
997
|
async downloadAudio(notebookId, artifactId) {
|
|
@@ -1380,14 +1243,14 @@ function isTrustedDomain(url) {
|
|
|
1380
1243
|
|
|
1381
1244
|
// src/api/chat.ts
|
|
1382
1245
|
init_enums();
|
|
1383
|
-
init_errors();
|
|
1384
1246
|
var QUERY_URL = "https://notebooklm.google.com/_/LabsTailwindUi/data/google.internal.labs.tailwind.orchestration.v1.LabsTailwindOrchestrationService/GenerateFreeFormStreamed";
|
|
1385
1247
|
var DEFAULT_BL = "boq_labs-tailwind-frontend_20260301.03_p0";
|
|
1386
1248
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1387
1249
|
var ChatAPI = class {
|
|
1388
|
-
constructor(rpc, auth) {
|
|
1250
|
+
constructor(rpc, auth, refreshAuth) {
|
|
1389
1251
|
this.rpc = rpc;
|
|
1390
1252
|
this.auth = auth;
|
|
1253
|
+
this.refreshAuth = refreshAuth;
|
|
1391
1254
|
}
|
|
1392
1255
|
conversationCache = /* @__PURE__ */ new Map();
|
|
1393
1256
|
reqid = Math.floor(Math.random() * 9e5) + 1e5;
|
|
@@ -1417,20 +1280,7 @@ var ChatAPI = class {
|
|
|
1417
1280
|
const bodyParts = [`f.req=${encodeURIComponent(fReq)}`];
|
|
1418
1281
|
if (this.auth.csrfToken) bodyParts.push(`at=${encodeURIComponent(this.auth.csrfToken)}`);
|
|
1419
1282
|
const body = bodyParts.join("&") + "&";
|
|
1420
|
-
|
|
1421
|
-
try {
|
|
1422
|
-
response = await fetch(`${QUERY_URL}?${urlParams.toString()}`, {
|
|
1423
|
-
method: "POST",
|
|
1424
|
-
headers: {
|
|
1425
|
-
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
1426
|
-
Cookie: this.auth.cookieHeader
|
|
1427
|
-
},
|
|
1428
|
-
body
|
|
1429
|
-
});
|
|
1430
|
-
} catch (e) {
|
|
1431
|
-
throw new ChatError(`Chat request failed: ${String(e)}`);
|
|
1432
|
-
}
|
|
1433
|
-
if (!response.ok) throw new ChatError(`Chat request failed: HTTP ${response.status}`);
|
|
1283
|
+
const response = await this._postChatRequest(`${QUERY_URL}?${urlParams.toString()}`, body);
|
|
1434
1284
|
const text = await response.text();
|
|
1435
1285
|
const { answer, conversationId: serverConvId, references } = parseStreamingResponse(text);
|
|
1436
1286
|
const finalConvId = serverConvId ?? conversationId;
|
|
@@ -1490,12 +1340,47 @@ var ChatAPI = class {
|
|
|
1490
1340
|
}
|
|
1491
1341
|
return null;
|
|
1492
1342
|
}
|
|
1343
|
+
async getHistory(notebookId, limit = 100, conversationId) {
|
|
1344
|
+
const convId = conversationId ?? await this.getLastConversationId(notebookId);
|
|
1345
|
+
if (!convId) return [];
|
|
1346
|
+
const params = [[], null, null, convId, limit];
|
|
1347
|
+
const result = await this.rpc.call(RPCMethod.GET_CONVERSATION_TURNS, params, {
|
|
1348
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1349
|
+
allowNull: true
|
|
1350
|
+
});
|
|
1351
|
+
if (!Array.isArray(result) || !Array.isArray(result[0])) return [];
|
|
1352
|
+
const rawTurns = [...result[0]].reverse();
|
|
1353
|
+
const history = [];
|
|
1354
|
+
let i = 0;
|
|
1355
|
+
while (i < rawTurns.length) {
|
|
1356
|
+
const turn = rawTurns[i];
|
|
1357
|
+
if (!Array.isArray(turn) || turn.length < 3) {
|
|
1358
|
+
i++;
|
|
1359
|
+
continue;
|
|
1360
|
+
}
|
|
1361
|
+
if (turn[2] === 1 && turn.length > 3) {
|
|
1362
|
+
const query = typeof turn[3] === "string" ? turn[3] : "";
|
|
1363
|
+
let answer = "";
|
|
1364
|
+
const next = rawTurns[i + 1];
|
|
1365
|
+
if (Array.isArray(next) && next.length > 4 && next[2] === 2) {
|
|
1366
|
+
try {
|
|
1367
|
+
answer = String(next[4][0][0] ?? "");
|
|
1368
|
+
} catch {
|
|
1369
|
+
}
|
|
1370
|
+
i++;
|
|
1371
|
+
}
|
|
1372
|
+
history.push([query, answer]);
|
|
1373
|
+
}
|
|
1374
|
+
i++;
|
|
1375
|
+
}
|
|
1376
|
+
return history;
|
|
1377
|
+
}
|
|
1493
1378
|
/**
|
|
1494
1379
|
* Low-level chat configuration. Set goal, response length, and optional
|
|
1495
1380
|
* custom instructions directly. Persists on the server per notebook.
|
|
1496
1381
|
* Use `setMode()` for preset combinations instead.
|
|
1497
1382
|
*/
|
|
1498
|
-
async configure(notebookId, goal, length, customPrompt) {
|
|
1383
|
+
async configure(notebookId, goal = ChatGoal.DEFAULT, length = ChatResponseLength.DEFAULT, customPrompt) {
|
|
1499
1384
|
if (goal === ChatGoal.CUSTOM && !customPrompt) {
|
|
1500
1385
|
throw new Error("customPrompt is required when goal is ChatGoal.CUSTOM");
|
|
1501
1386
|
}
|
|
@@ -1527,6 +1412,14 @@ var ChatAPI = class {
|
|
|
1527
1412
|
this.conversationCache.clear();
|
|
1528
1413
|
}
|
|
1529
1414
|
}
|
|
1415
|
+
getCachedTurns(conversationId) {
|
|
1416
|
+
const turns = this.conversationCache.get(conversationId) ?? [];
|
|
1417
|
+
return turns.map((turn) => ({
|
|
1418
|
+
query: turn.query,
|
|
1419
|
+
answer: turn.answer,
|
|
1420
|
+
turnNumber: turn.turnNumber
|
|
1421
|
+
}));
|
|
1422
|
+
}
|
|
1530
1423
|
_buildHistory(conversationId) {
|
|
1531
1424
|
const turns = this.conversationCache.get(conversationId) ?? [];
|
|
1532
1425
|
if (!turns.length) return null;
|
|
@@ -1537,6 +1430,27 @@ var ChatAPI = class {
|
|
|
1537
1430
|
}
|
|
1538
1431
|
return history;
|
|
1539
1432
|
}
|
|
1433
|
+
async _postChatRequest(url, body, retried = false) {
|
|
1434
|
+
let response;
|
|
1435
|
+
try {
|
|
1436
|
+
response = await fetch(url, {
|
|
1437
|
+
method: "POST",
|
|
1438
|
+
headers: {
|
|
1439
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
1440
|
+
Cookie: this.auth.cookieHeader
|
|
1441
|
+
},
|
|
1442
|
+
body
|
|
1443
|
+
});
|
|
1444
|
+
} catch (e) {
|
|
1445
|
+
throw new ChatError(`Chat request failed: ${String(e)}`);
|
|
1446
|
+
}
|
|
1447
|
+
if ((response.status === 401 || response.status === 403) && !retried && this.refreshAuth) {
|
|
1448
|
+
await this.refreshAuth();
|
|
1449
|
+
return this._postChatRequest(url, body, true);
|
|
1450
|
+
}
|
|
1451
|
+
if (!response.ok) throw new ChatError(`Chat request failed: HTTP ${response.status}`);
|
|
1452
|
+
return response;
|
|
1453
|
+
}
|
|
1540
1454
|
};
|
|
1541
1455
|
function parseStreamingResponse(rawText) {
|
|
1542
1456
|
let text = rawText;
|
|
@@ -1693,6 +1607,12 @@ var NotebooksAPI = class {
|
|
|
1693
1607
|
async removeFromRecent(notebookId) {
|
|
1694
1608
|
await this.rpc.call(RPCMethod.REMOVE_RECENTLY_VIEWED, [notebookId], { allowNull: true });
|
|
1695
1609
|
}
|
|
1610
|
+
async getRaw(notebookId) {
|
|
1611
|
+
const params = [notebookId, null, [2], null, 0];
|
|
1612
|
+
return this.rpc.call(RPCMethod.GET_NOTEBOOK, params, {
|
|
1613
|
+
sourcePath: `/notebook/${notebookId}`
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1696
1616
|
async getDescription(notebookId) {
|
|
1697
1617
|
const params = [notebookId, [2]];
|
|
1698
1618
|
const result = await this.rpc.call(RPCMethod.SUMMARIZE, params, {
|
|
@@ -1720,6 +1640,41 @@ var NotebooksAPI = class {
|
|
|
1720
1640
|
}
|
|
1721
1641
|
return { summary, suggestedTopics };
|
|
1722
1642
|
}
|
|
1643
|
+
async share(notebookId, publicAccess = true, artifactId) {
|
|
1644
|
+
const shareOptions = publicAccess ? [1] : [0];
|
|
1645
|
+
const params = artifactId ? [shareOptions, notebookId, artifactId] : [shareOptions, notebookId];
|
|
1646
|
+
await this.rpc.call(RPCMethod.SHARE_ARTIFACT, params, {
|
|
1647
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1648
|
+
allowNull: true
|
|
1649
|
+
});
|
|
1650
|
+
return {
|
|
1651
|
+
public: publicAccess,
|
|
1652
|
+
url: publicAccess ? this.getShareUrl(notebookId, artifactId) : null,
|
|
1653
|
+
artifactId: artifactId ?? null
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
getShareUrl(notebookId, artifactId) {
|
|
1657
|
+
const baseUrl = `https://notebooklm.google.com/notebook/${notebookId}`;
|
|
1658
|
+
return artifactId ? `${baseUrl}?artifactId=${artifactId}` : baseUrl;
|
|
1659
|
+
}
|
|
1660
|
+
async getMetadata(notebookId) {
|
|
1661
|
+
const raw = await this.getRaw(notebookId);
|
|
1662
|
+
const notebookData = Array.isArray(raw) && raw.length > 0 && Array.isArray(raw[0]) ? raw[0] : [];
|
|
1663
|
+
const notebook = parseNotebook(notebookData);
|
|
1664
|
+
const sourcesRaw = Array.isArray(notebookData[1]) ? notebookData[1] : [];
|
|
1665
|
+
const sources = sourcesRaw.filter((source) => Array.isArray(source) && source.length > 0).map((source) => parseSource(source));
|
|
1666
|
+
return {
|
|
1667
|
+
id: notebook.id,
|
|
1668
|
+
title: notebook.title,
|
|
1669
|
+
createdAt: notebook.createdAt,
|
|
1670
|
+
isOwner: notebook.isOwner,
|
|
1671
|
+
sources: sources.map((source) => ({
|
|
1672
|
+
kind: source.kind,
|
|
1673
|
+
title: source.title,
|
|
1674
|
+
url: source.url
|
|
1675
|
+
}))
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1723
1678
|
};
|
|
1724
1679
|
|
|
1725
1680
|
// src/api/notes.ts
|
|
@@ -1732,6 +1687,10 @@ var NotesAPI = class {
|
|
|
1732
1687
|
const all = await this._fetchAll(notebookId);
|
|
1733
1688
|
return all.filter((n) => !this._isMindMap(n.content));
|
|
1734
1689
|
}
|
|
1690
|
+
async get(notebookId, noteId) {
|
|
1691
|
+
const all = await this._fetchAll(notebookId);
|
|
1692
|
+
return all.find((note) => note.id === noteId) ?? null;
|
|
1693
|
+
}
|
|
1735
1694
|
async listMindMaps(notebookId) {
|
|
1736
1695
|
const all = await this._fetchAll(notebookId);
|
|
1737
1696
|
return all.filter((n) => this._isMindMap(n.content));
|
|
@@ -1763,6 +1722,9 @@ var NotesAPI = class {
|
|
|
1763
1722
|
});
|
|
1764
1723
|
return true;
|
|
1765
1724
|
}
|
|
1725
|
+
async deleteMindMap(notebookId, mindMapId) {
|
|
1726
|
+
return this.delete(notebookId, mindMapId);
|
|
1727
|
+
}
|
|
1766
1728
|
async _fetchAll(notebookId) {
|
|
1767
1729
|
const result = await this.rpc.call(RPCMethod.GET_NOTES_AND_MIND_MAPS, [notebookId], {
|
|
1768
1730
|
sourcePath: `/notebook/${notebookId}`,
|
|
@@ -2139,7 +2101,6 @@ function parseShareStatus(data, notebookId) {
|
|
|
2139
2101
|
|
|
2140
2102
|
// src/api/sources.ts
|
|
2141
2103
|
init_enums();
|
|
2142
|
-
init_errors();
|
|
2143
2104
|
var UPLOAD_URL = "https://notebooklm.google.com/upload/_/";
|
|
2144
2105
|
var SourcesAPI = class {
|
|
2145
2106
|
constructor(rpc, auth) {
|
|
@@ -2422,6 +2383,29 @@ var SourcesAPI = class {
|
|
|
2422
2383
|
});
|
|
2423
2384
|
return true;
|
|
2424
2385
|
}
|
|
2386
|
+
async rename(notebookId, sourceId, newTitle) {
|
|
2387
|
+
const params = [null, [sourceId], [[[newTitle]]]];
|
|
2388
|
+
const result = await this.rpc.call(RPCMethod.UPDATE_SOURCE, params, {
|
|
2389
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
2390
|
+
allowNull: true
|
|
2391
|
+
});
|
|
2392
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
2393
|
+
try {
|
|
2394
|
+
const parsed = parseSource(result);
|
|
2395
|
+
return parsed.title ? parsed : { ...parsed, title: newTitle };
|
|
2396
|
+
} catch {
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
return {
|
|
2400
|
+
id: sourceId,
|
|
2401
|
+
title: newTitle,
|
|
2402
|
+
url: null,
|
|
2403
|
+
kind: "unknown",
|
|
2404
|
+
createdAt: null,
|
|
2405
|
+
status: "ready",
|
|
2406
|
+
_typeCode: null
|
|
2407
|
+
};
|
|
2408
|
+
}
|
|
2425
2409
|
async waitUntilReady(notebookId, sourceId, timeout = 120, initialInterval = 1, maxInterval = 10, backoffFactor = 1.5) {
|
|
2426
2410
|
const deadline = Date.now() + timeout * 1e3;
|
|
2427
2411
|
let interval = initialInterval;
|
|
@@ -2440,6 +2424,20 @@ var SourcesAPI = class {
|
|
|
2440
2424
|
}
|
|
2441
2425
|
throw new SourceTimeoutError(sourceId, timeout, lastStatus);
|
|
2442
2426
|
}
|
|
2427
|
+
async waitForSources(notebookId, sourceIds, timeout = 120, initialInterval = 1, maxInterval = 10, backoffFactor = 1.5) {
|
|
2428
|
+
return Promise.all(
|
|
2429
|
+
sourceIds.map(
|
|
2430
|
+
(sourceId) => this.waitUntilReady(
|
|
2431
|
+
notebookId,
|
|
2432
|
+
sourceId,
|
|
2433
|
+
timeout,
|
|
2434
|
+
initialInterval,
|
|
2435
|
+
maxInterval,
|
|
2436
|
+
backoffFactor
|
|
2437
|
+
)
|
|
2438
|
+
)
|
|
2439
|
+
);
|
|
2440
|
+
}
|
|
2443
2441
|
};
|
|
2444
2442
|
function extractSourceId(result) {
|
|
2445
2443
|
if (Array.isArray(result)) {
|
|
@@ -2472,18 +2470,169 @@ function extractAllText(data, maxDepth = 100) {
|
|
|
2472
2470
|
function sleep2(ms) {
|
|
2473
2471
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2474
2472
|
}
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2473
|
+
var DEFAULT_SESSION_FILE = join(homedir(), ".notebooklm", "session.json");
|
|
2474
|
+
function loadCookiesFromFile(filePath) {
|
|
2475
|
+
let raw;
|
|
2476
|
+
try {
|
|
2477
|
+
raw = readFileSync(filePath, "utf-8");
|
|
2478
|
+
} catch {
|
|
2479
|
+
throw new AuthError(`Session file not found: ${filePath}
|
|
2480
|
+
Run: npx notebooklm-sdk login`);
|
|
2481
|
+
}
|
|
2482
|
+
return extractCookiesFromStorageState(JSON.parse(raw));
|
|
2483
|
+
}
|
|
2484
|
+
function loadCookiesFromObject(storageState) {
|
|
2485
|
+
return extractCookiesFromStorageState(storageState);
|
|
2486
|
+
}
|
|
2487
|
+
function buildGoogleCookieHeader(storageState) {
|
|
2488
|
+
const map = {};
|
|
2489
|
+
for (const c of storageState.cookies ?? []) {
|
|
2490
|
+
if (c.domain === ".google.com" && c.name && c.value) {
|
|
2491
|
+
map[c.name] = map[c.name] ?? c.value;
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
return buildCookieHeader(map);
|
|
2495
|
+
}
|
|
2496
|
+
function loadCookiesFromMap(map) {
|
|
2497
|
+
return { ...map };
|
|
2498
|
+
}
|
|
2499
|
+
function loadCookiesFromString(cookieStr) {
|
|
2500
|
+
const map = {};
|
|
2501
|
+
for (const part of cookieStr.split(/;\s*/)) {
|
|
2502
|
+
const idx = part.indexOf("=");
|
|
2503
|
+
if (idx > 0) {
|
|
2504
|
+
const name = part.slice(0, idx).trim();
|
|
2505
|
+
const value = part.slice(idx + 1).trim();
|
|
2506
|
+
if (name) map[name] = value;
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
return map;
|
|
2510
|
+
}
|
|
2511
|
+
function extractCookiesFromStorageState(storageState) {
|
|
2512
|
+
const cookies = {};
|
|
2513
|
+
for (const cookie of storageState.cookies ?? []) {
|
|
2514
|
+
const { domain, name, value } = cookie;
|
|
2515
|
+
if (!isAllowedDomain(domain) || !name) continue;
|
|
2516
|
+
const isBase = domain === ".google.com";
|
|
2517
|
+
if (!(name in cookies) || isBase) {
|
|
2518
|
+
cookies[name] = value;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
if (!cookies["SID"]) {
|
|
2522
|
+
throw new AuthError(
|
|
2523
|
+
"Missing required cookie: SID. Session may be invalid or expired.\nRun: npx notebooklm-sdk login"
|
|
2524
|
+
);
|
|
2525
|
+
}
|
|
2526
|
+
return cookies;
|
|
2527
|
+
}
|
|
2528
|
+
function isAllowedDomain(domain) {
|
|
2529
|
+
if (domain === ".google.com" || domain === "notebooklm.google.com" || domain === ".googleusercontent.com") {
|
|
2530
|
+
return true;
|
|
2531
|
+
}
|
|
2532
|
+
if (domain.startsWith(".google.")) {
|
|
2533
|
+
return true;
|
|
2534
|
+
}
|
|
2535
|
+
return false;
|
|
2536
|
+
}
|
|
2537
|
+
function buildCookieHeader(cookies) {
|
|
2538
|
+
return Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join("; ");
|
|
2539
|
+
}
|
|
2540
|
+
var NOTEBOOKLM_URL = "https://notebooklm.google.com/";
|
|
2541
|
+
async function fetchTokens(cookies) {
|
|
2542
|
+
const cookieHeader = buildCookieHeader(cookies);
|
|
2543
|
+
const response = await fetch(NOTEBOOKLM_URL, {
|
|
2544
|
+
headers: { Cookie: cookieHeader },
|
|
2545
|
+
redirect: "follow"
|
|
2546
|
+
});
|
|
2547
|
+
if (!response.ok) {
|
|
2548
|
+
throw new AuthError(`Failed to fetch NotebookLM page: HTTP ${response.status}`);
|
|
2549
|
+
}
|
|
2550
|
+
const finalUrl = response.url;
|
|
2551
|
+
if (isGoogleAuthRedirect(finalUrl)) {
|
|
2552
|
+
throw new AuthError(`Redirected to login page: ${finalUrl}. Cookies may be expired.`);
|
|
2553
|
+
}
|
|
2554
|
+
const html = await response.text();
|
|
2555
|
+
const csrfToken = extractCsrfToken(html, finalUrl);
|
|
2556
|
+
const sessionId = extractSessionId(html, finalUrl);
|
|
2557
|
+
return { csrfToken, sessionId };
|
|
2558
|
+
}
|
|
2559
|
+
async function refreshAuthTokens(auth) {
|
|
2560
|
+
const { csrfToken, sessionId } = await fetchTokens(auth.cookies);
|
|
2561
|
+
auth.csrfToken = csrfToken;
|
|
2562
|
+
auth.sessionId = sessionId;
|
|
2563
|
+
return auth;
|
|
2564
|
+
}
|
|
2565
|
+
function extractCsrfToken(html, finalUrl) {
|
|
2566
|
+
const match = /"SNlM0e"\s*:\s*"([^"]+)"/.exec(html);
|
|
2567
|
+
if (!match?.[1]) {
|
|
2568
|
+
if (isGoogleAuthRedirect(finalUrl) || html.includes("accounts.google.com")) {
|
|
2569
|
+
throw new AuthError("Session expired or invalid.\nRun: npx notebooklm-sdk login");
|
|
2570
|
+
}
|
|
2571
|
+
throw new AuthError("CSRF token (SNlM0e) not found in NotebookLM page HTML.");
|
|
2572
|
+
}
|
|
2573
|
+
return match[1];
|
|
2574
|
+
}
|
|
2575
|
+
function extractSessionId(html, finalUrl) {
|
|
2576
|
+
const match = /"FdrFJe"\s*:\s*"([^"]+)"/.exec(html);
|
|
2577
|
+
if (!match?.[1]) {
|
|
2578
|
+
if (isGoogleAuthRedirect(finalUrl) || html.includes("accounts.google.com")) {
|
|
2579
|
+
throw new AuthError("Session expired or invalid.\nRun: npx notebooklm-sdk login");
|
|
2580
|
+
}
|
|
2581
|
+
throw new AuthError("Session ID (FdrFJe) not found in NotebookLM page HTML.");
|
|
2582
|
+
}
|
|
2583
|
+
return match[1];
|
|
2584
|
+
}
|
|
2585
|
+
function isGoogleAuthRedirect(url) {
|
|
2586
|
+
return url.includes("accounts.google.com") || url.includes("signin");
|
|
2587
|
+
}
|
|
2588
|
+
async function connect(opts = {}) {
|
|
2589
|
+
let cookieMap;
|
|
2590
|
+
let googleCookieHeader = null;
|
|
2591
|
+
if (opts.cookies) {
|
|
2592
|
+
cookieMap = loadCookiesFromString(opts.cookies);
|
|
2593
|
+
} else if (opts.cookiesFile) {
|
|
2594
|
+
cookieMap = loadCookiesFromFile(opts.cookiesFile);
|
|
2595
|
+
} else if (opts.cookiesObject) {
|
|
2596
|
+
if ("cookies" in opts.cookiesObject && Array.isArray(opts.cookiesObject.cookies)) {
|
|
2597
|
+
const storageState = opts.cookiesObject;
|
|
2598
|
+
cookieMap = loadCookiesFromObject(storageState);
|
|
2599
|
+
googleCookieHeader = buildGoogleCookieHeader(storageState);
|
|
2600
|
+
} else {
|
|
2601
|
+
cookieMap = loadCookiesFromMap(opts.cookiesObject);
|
|
2602
|
+
}
|
|
2603
|
+
} else {
|
|
2604
|
+
const envCookies = process.env["NOTEBOOKLM_COOKIES"];
|
|
2605
|
+
const envFile = process.env["NOTEBOOKLM_COOKIES_FILE"];
|
|
2606
|
+
if (envFile) {
|
|
2607
|
+
cookieMap = loadCookiesFromFile(envFile);
|
|
2608
|
+
} else if (existsSync(DEFAULT_SESSION_FILE)) {
|
|
2609
|
+
const raw = readFileSync(DEFAULT_SESSION_FILE, "utf-8");
|
|
2610
|
+
const storageState = JSON.parse(raw);
|
|
2611
|
+
cookieMap = loadCookiesFromObject(storageState);
|
|
2612
|
+
googleCookieHeader = buildGoogleCookieHeader(storageState);
|
|
2613
|
+
} else if (existsSync("storage_state.json")) {
|
|
2614
|
+
const raw = readFileSync("storage_state.json", "utf-8");
|
|
2615
|
+
const storageState = JSON.parse(raw);
|
|
2616
|
+
cookieMap = loadCookiesFromObject(storageState);
|
|
2617
|
+
googleCookieHeader = buildGoogleCookieHeader(storageState);
|
|
2618
|
+
} else if (envCookies) {
|
|
2619
|
+
cookieMap = loadCookiesFromString(envCookies);
|
|
2620
|
+
} else {
|
|
2621
|
+
throw new AuthError("No session found. Run: npx notebooklm-sdk login");
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
const { csrfToken, sessionId } = await fetchTokens(cookieMap);
|
|
2625
|
+
const cookieHeader = buildCookieHeader(cookieMap);
|
|
2626
|
+
return {
|
|
2627
|
+
cookies: cookieMap,
|
|
2628
|
+
csrfToken,
|
|
2629
|
+
sessionId,
|
|
2630
|
+
cookieHeader,
|
|
2631
|
+
googleCookieHeader: googleCookieHeader ?? cookieHeader
|
|
2632
|
+
};
|
|
2633
|
+
}
|
|
2484
2634
|
|
|
2485
2635
|
// src/rpc/decoder.ts
|
|
2486
|
-
init_errors();
|
|
2487
2636
|
function stripAntiXSSI(response) {
|
|
2488
2637
|
if (response.startsWith(")]}'")) {
|
|
2489
2638
|
const match = /\)\]\}'\r?\n/.exec(response);
|
|
@@ -2667,11 +2816,13 @@ var DEFAULT_TIMEOUT_MS = 3e4;
|
|
|
2667
2816
|
var RPCCore = class {
|
|
2668
2817
|
auth;
|
|
2669
2818
|
timeoutMs;
|
|
2670
|
-
|
|
2819
|
+
refreshAuth;
|
|
2820
|
+
constructor(auth, timeoutMs = DEFAULT_TIMEOUT_MS, refreshAuth) {
|
|
2671
2821
|
this.auth = auth;
|
|
2672
2822
|
this.timeoutMs = timeoutMs;
|
|
2823
|
+
this.refreshAuth = refreshAuth;
|
|
2673
2824
|
}
|
|
2674
|
-
async call(methodId, params, opts = {}) {
|
|
2825
|
+
async call(methodId, params, opts = {}, retried = false) {
|
|
2675
2826
|
const sourcePath = opts.sourcePath ?? "/";
|
|
2676
2827
|
const allowNull = opts.allowNull ?? false;
|
|
2677
2828
|
const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
|
|
@@ -2718,6 +2869,10 @@ var RPCCore = class {
|
|
|
2718
2869
|
});
|
|
2719
2870
|
}
|
|
2720
2871
|
if (status === 401 || status === 403) {
|
|
2872
|
+
if (!retried && this.refreshAuth) {
|
|
2873
|
+
await this.refreshAuth();
|
|
2874
|
+
return this.call(methodId, params, opts, true);
|
|
2875
|
+
}
|
|
2721
2876
|
throw new AuthError(`HTTP ${status} calling ${methodId}: authentication required`, {
|
|
2722
2877
|
methodId
|
|
2723
2878
|
});
|
|
@@ -2770,12 +2925,13 @@ var RPCCore = class {
|
|
|
2770
2925
|
var NotebookLMClient = class _NotebookLMClient {
|
|
2771
2926
|
constructor(auth, opts = {}) {
|
|
2772
2927
|
this.auth = auth;
|
|
2773
|
-
const
|
|
2928
|
+
const refreshAuth = this.refreshTokens.bind(this);
|
|
2929
|
+
const rpc = new RPCCore(auth, opts.timeoutMs, refreshAuth);
|
|
2774
2930
|
this.notebooks = new NotebooksAPI(rpc);
|
|
2775
2931
|
this.sources = new SourcesAPI(rpc, auth);
|
|
2776
2932
|
this.notes = new NotesAPI(rpc);
|
|
2777
2933
|
this.artifacts = new ArtifactsAPI(rpc, auth, this.notes);
|
|
2778
|
-
this.chat = new ChatAPI(rpc, auth);
|
|
2934
|
+
this.chat = new ChatAPI(rpc, auth, refreshAuth);
|
|
2779
2935
|
this.research = new ResearchAPI(rpc);
|
|
2780
2936
|
this.settings = new SettingsAPI(rpc);
|
|
2781
2937
|
this.sharing = new SharingAPI(rpc);
|
|
@@ -2788,6 +2944,7 @@ var NotebookLMClient = class _NotebookLMClient {
|
|
|
2788
2944
|
research;
|
|
2789
2945
|
settings;
|
|
2790
2946
|
sharing;
|
|
2947
|
+
refreshPromise = null;
|
|
2791
2948
|
/**
|
|
2792
2949
|
* Connect to NotebookLM using cookies.
|
|
2793
2950
|
* Fetches CSRF and session tokens from the NotebookLM homepage.
|
|
@@ -2800,16 +2957,17 @@ var NotebookLMClient = class _NotebookLMClient {
|
|
|
2800
2957
|
* Refresh CSRF and session tokens (e.g. if they expire mid-session).
|
|
2801
2958
|
*/
|
|
2802
2959
|
async refreshTokens() {
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2960
|
+
if (!this.refreshPromise) {
|
|
2961
|
+
this.refreshPromise = refreshAuthTokens(this.auth).then(() => void 0).finally(() => {
|
|
2962
|
+
this.refreshPromise = null;
|
|
2963
|
+
});
|
|
2964
|
+
}
|
|
2965
|
+
await this.refreshPromise;
|
|
2807
2966
|
}
|
|
2808
2967
|
};
|
|
2809
2968
|
|
|
2810
2969
|
// src/index.ts
|
|
2811
2970
|
init_enums();
|
|
2812
|
-
init_errors();
|
|
2813
2971
|
|
|
2814
2972
|
export { ArtifactDownloadError, ArtifactError, ArtifactNotFoundError, ArtifactNotReadyError, ArtifactParseError, ArtifactTypeCode, ArtifactsAPI, AudioFormat, AudioLength, AuthError, ChatAPI, ChatError, ChatGoal, ChatMode, ChatResponseLength, ClientError, DriveMimeType, ExportType, InfographicDetail, InfographicOrientation, InfographicStyle, NetworkError, NotebookError, NotebookLMClient, NotebookLMError, NotebookNotFoundError, NotebooksAPI, NotesAPI, QuizDifficulty, QuizQuantity, RPCError, RPCMethod, RPCTimeoutError, RateLimitError, ResearchAPI, ServerError, SettingsAPI, ShareAccess, SharePermission, ShareViewLevel, SharingAPI, SlideDeckFormat, SlideDeckLength, SourceAddError, SourceError, SourceNotFoundError, SourceProcessingError, SourceTimeoutError, SourcesAPI, VideoFormat, VideoStyle, connect };
|
|
2815
2973
|
//# sourceMappingURL=index.js.map
|