itd-api 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/index.cjs +572 -374
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +833 -791
- package/dist/index.d.ts +833 -791
- package/dist/index.js +565 -367
- package/dist/index.js.map +1 -1
- package/dist/{multi-storage-D1keK2Op.cjs → multi-storage-C8R5Crwo.cjs} +33 -219
- package/dist/multi-storage-C8R5Crwo.cjs.map +1 -0
- package/dist/{multi-storage-CyMe404l.js → multi-storage-D4h6QA-w.js} +26 -200
- package/dist/multi-storage-D4h6QA-w.js.map +1 -0
- package/dist/{multi-storage-NDqzRQcD.d.cts → multi-storage-DP_ujJw1.d.cts} +3 -17
- package/dist/{multi-storage-BhcA2Izn.d.ts → multi-storage-DwaIh24p.d.ts} +3 -17
- package/dist/node.cjs +1 -1
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +1 -1
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
- package/dist/multi-storage-CyMe404l.js.map +0 -1
- package/dist/multi-storage-D1keK2Op.cjs.map +0 -1
|
@@ -332,7 +332,7 @@ var CookieJar = class {
|
|
|
332
332
|
}
|
|
333
333
|
};
|
|
334
334
|
//#endregion
|
|
335
|
-
//#region src/core/attachments.ts
|
|
335
|
+
//#region src/core/attachments/contracts.ts
|
|
336
336
|
/** Способ передачи содержимого вложения. */
|
|
337
337
|
const FileTransferMode = Object.freeze({
|
|
338
338
|
/** Сначала получить файл целиком, затем отправить его как `Blob`. */
|
|
@@ -344,44 +344,16 @@ const FileTransferMode = Object.freeze({
|
|
|
344
344
|
const DEFAULT_FILE_STREAM_BUFFER_BYTES = 4 * 1024 * 1024;
|
|
345
345
|
/** Предел размера файла, скачиваемого по адресу, — 100 МиБ. */
|
|
346
346
|
const DEFAULT_URL_FILE_MAX_BYTES = 100 * 1024 * 1024;
|
|
347
|
-
|
|
348
|
-
|
|
347
|
+
//#endregion
|
|
348
|
+
//#region src/core/attachments/limits.ts
|
|
349
349
|
/** Проверяет числовую границу до обращения к источнику. */
|
|
350
350
|
function optionalBytes(value, name) {
|
|
351
351
|
if (value === void 0) return void 0;
|
|
352
352
|
if (!Number.isFinite(value) || value < 0 || !Number.isInteger(value)) throw new require_storage.ItdConfigError(`${name} должен быть неотрицательным целым числом, получено: ${value}`);
|
|
353
353
|
return value;
|
|
354
354
|
}
|
|
355
|
-
/**
|
|
356
|
-
function
|
|
357
|
-
const mode = options.mode ?? FileTransferMode.Buffer;
|
|
358
|
-
if (mode !== FileTransferMode.Buffer && mode !== FileTransferMode.Stream) throw new require_storage.ItdConfigError(`mode вложения должен быть 'buffer' или 'stream', получено: ${mode}`);
|
|
359
|
-
if (mode === FileTransferMode.Stream && typeof ReadableStream === "undefined") throw new require_storage.ItdConfigError("эта среда не поддерживает ReadableStream; используйте mode: 'buffer'");
|
|
360
|
-
const maxBytes = optionalBytes(options.maxBytes ?? defaultMaxBytes, "maxBytes");
|
|
361
|
-
const streamBufferBytes = optionalBytes(options.streamBufferBytes ?? 4194304, "streamBufferBytes") ?? 4194304;
|
|
362
|
-
if (streamBufferBytes === 0) throw new require_storage.ItdConfigError("streamBufferBytes должен быть больше нуля");
|
|
363
|
-
return {
|
|
364
|
-
mode,
|
|
365
|
-
maxBytes,
|
|
366
|
-
streamBufferBytes
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
/** Убирает параметры MIME и приводит его к форме для сравнения. */
|
|
370
|
-
function normalizeMimeType(contentType) {
|
|
371
|
-
return contentType?.split(";", 1)[0]?.trim().toLowerCase() || void 0;
|
|
372
|
-
}
|
|
373
|
-
/** Достаёт имя файла из пути URL. */
|
|
374
|
-
function filenameFromUrl(url) {
|
|
375
|
-
const last = url.pathname.split("/").pop();
|
|
376
|
-
if (!last) return void 0;
|
|
377
|
-
try {
|
|
378
|
-
return decodeURIComponent(last) || void 0;
|
|
379
|
-
} catch {
|
|
380
|
-
return last;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
/** Создаёт ошибку превышения размера. */
|
|
384
|
-
function tooLarge(url, limit, actual) {
|
|
355
|
+
/** Создаёт типизированную ошибку превышения размера вложения. */
|
|
356
|
+
function fileTooLarge(url, limit, actual) {
|
|
385
357
|
return new require_storage.ItdFileError(`файл${url ? ` по адресу ${url}` : ""} больше предела в ${limit} байт: ${actual}`, {
|
|
386
358
|
reason: require_storage.ItdFileErrorReason.TooLarge,
|
|
387
359
|
...url ? { url } : {},
|
|
@@ -389,64 +361,15 @@ function tooLarge(url, limit, actual) {
|
|
|
389
361
|
actual
|
|
390
362
|
});
|
|
391
363
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const size = Number(header);
|
|
397
|
-
if (!Number.isFinite(size) || size < 0 || !Number.isInteger(size)) return void 0;
|
|
398
|
-
if (maxBytes !== void 0 && size > maxBytes) throw tooLarge(url, maxBytes, size);
|
|
399
|
-
return size;
|
|
400
|
-
}
|
|
401
|
-
/** Получает HTTP-ответ источника и проверяет его статус. */
|
|
402
|
-
async function fetchFile(target, options, context) {
|
|
403
|
-
let requested;
|
|
404
|
-
try {
|
|
405
|
-
requested = new URL(target);
|
|
406
|
-
} catch {
|
|
407
|
-
throw new require_storage.ItdConfigError(`«${target}» не разбирается как адрес`);
|
|
408
|
-
}
|
|
409
|
-
if (requested.protocol !== "http:" && requested.protocol !== "https:") throw new require_storage.ItdConfigError(`вложение по адресу поддерживает только http и https, получено: ${requested.protocol}`);
|
|
410
|
-
let response;
|
|
411
|
-
try {
|
|
412
|
-
response = await context.fetch(requested, { ...context.signal ? { signal: context.signal } : {} });
|
|
413
|
-
} catch (error) {
|
|
414
|
-
if (context.signal?.aborted || error instanceof Error && error.name === "AbortError") throw error;
|
|
415
|
-
throw new require_storage.ItdFileError(`не удалось получить файл по адресу ${requested.href}`, {
|
|
416
|
-
reason: require_storage.ItdFileErrorReason.Network,
|
|
417
|
-
url: requested.href,
|
|
418
|
-
retryable: true,
|
|
419
|
-
cause: error
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
const finalUrl = response.url ? new URL(response.url) : requested;
|
|
423
|
-
if (!response.ok) {
|
|
424
|
-
await response.body?.cancel().catch(() => {});
|
|
425
|
-
throw new require_storage.ItdFileError(`источник ${finalUrl.href} ответил статусом ${response.status}`, {
|
|
426
|
-
reason: require_storage.ItdFileErrorReason.Http,
|
|
427
|
-
url: finalUrl.href,
|
|
428
|
-
status: response.status,
|
|
429
|
-
retryable: response.status === 408 || response.status === 429 || response.status >= 500
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
const { maxBytes } = resolveFileStreamOptions(options, DEFAULT_URL_FILE_MAX_BYTES);
|
|
433
|
-
let size;
|
|
434
|
-
try {
|
|
435
|
-
size = declaredSize(response, maxBytes, finalUrl.href);
|
|
436
|
-
} catch (error) {
|
|
437
|
-
await response.body?.cancel().catch(() => {});
|
|
438
|
-
throw error;
|
|
439
|
-
}
|
|
440
|
-
return {
|
|
441
|
-
response,
|
|
442
|
-
url: finalUrl,
|
|
443
|
-
size
|
|
444
|
-
};
|
|
445
|
-
}
|
|
364
|
+
//#endregion
|
|
365
|
+
//#region src/core/attachments/bounded-stream.ts
|
|
366
|
+
/** Потоки, на которые уже наложены счётчик размера и backpressure. */
|
|
367
|
+
const BOUNDED_FILE_STREAMS = /* @__PURE__ */ new WeakSet();
|
|
446
368
|
/** Приводит произвольный чанк потока к байтам. */
|
|
447
369
|
function asBytes(value) {
|
|
448
370
|
return value instanceof Uint8Array ? value : new Uint8Array(value);
|
|
449
371
|
}
|
|
372
|
+
/** Проверяет значение без обращения к методам потенциально чужого объекта. */
|
|
450
373
|
function isReadableByteStream(value) {
|
|
451
374
|
return typeof ReadableStream !== "undefined" && value instanceof ReadableStream;
|
|
452
375
|
}
|
|
@@ -496,7 +419,7 @@ function boundedFileStream(source, options = {}) {
|
|
|
496
419
|
finished = true;
|
|
497
420
|
await reader.cancel().catch(() => {});
|
|
498
421
|
cleanup();
|
|
499
|
-
controller.error(
|
|
422
|
+
controller.error(fileTooLarge(options.url, maxBytes, total));
|
|
500
423
|
return;
|
|
501
424
|
}
|
|
502
425
|
controller.enqueue(chunk);
|
|
@@ -531,119 +454,22 @@ function boundedFileStream(source, options = {}) {
|
|
|
531
454
|
function isBoundedFileStream(stream) {
|
|
532
455
|
return BOUNDED_FILE_STREAMS.has(stream);
|
|
533
456
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
streamBufferBytes,
|
|
545
|
-
...signal ? { signal } : {},
|
|
546
|
-
url,
|
|
547
|
-
retryableRead: true
|
|
548
|
-
}).getReader();
|
|
549
|
-
try {
|
|
550
|
-
for (;;) {
|
|
551
|
-
const next = await reader.read();
|
|
552
|
-
if (next.done) break;
|
|
553
|
-
chunks.push(next.value);
|
|
554
|
-
}
|
|
555
|
-
} finally {
|
|
556
|
-
reader.releaseLock();
|
|
557
|
-
}
|
|
558
|
-
return new Blob(chunks.map((chunk) => Uint8Array.from(chunk).buffer));
|
|
559
|
-
}
|
|
560
|
-
/** Скачивает файл целиком с ограничением размера. @internal */
|
|
561
|
-
async function downloadFile(target, options, context) {
|
|
562
|
-
const resolved = resolveFileStreamOptions(options, DEFAULT_URL_FILE_MAX_BYTES);
|
|
563
|
-
const { response, url } = await fetchFile(target, options, context);
|
|
564
|
-
const blob = await responseBlob(response, url.href, resolved.maxBytes, resolved.streamBufferBytes, context.signal);
|
|
565
|
-
const contentType = normalizeMimeType(options.contentType ?? response.headers.get("content-type") ?? void 0);
|
|
566
|
-
const filename = options.filename ?? filenameFromUrl(url);
|
|
567
|
-
return {
|
|
568
|
-
file: new Blob([blob], { type: contentType ?? "" }),
|
|
569
|
-
...filename ? { filename } : {},
|
|
570
|
-
...contentType ? { contentType } : {}
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
/** Открывает HTTP-ответ как ограниченный поток. @internal */
|
|
574
|
-
async function openUrlFile(target, options, context) {
|
|
575
|
-
const resolved = resolveFileStreamOptions(options, DEFAULT_URL_FILE_MAX_BYTES);
|
|
576
|
-
const { response, url, size } = await fetchFile(target, options, context);
|
|
577
|
-
if (!response.body) throw new require_storage.ItdFileError(`источник ${url.href} не предоставил потоковое тело`, {
|
|
578
|
-
reason: require_storage.ItdFileErrorReason.StreamUnavailable,
|
|
579
|
-
url: url.href
|
|
580
|
-
});
|
|
581
|
-
const stream = boundedFileStream(response.body, {
|
|
582
|
-
...resolved.maxBytes !== void 0 ? { maxBytes: resolved.maxBytes } : {},
|
|
583
|
-
streamBufferBytes: resolved.streamBufferBytes,
|
|
584
|
-
...context.signal ? { signal: context.signal } : {},
|
|
585
|
-
url: url.href,
|
|
586
|
-
retryableRead: true
|
|
587
|
-
});
|
|
588
|
-
const filename = options.filename ?? filenameFromUrl(url);
|
|
589
|
-
const contentType = normalizeMimeType(options.contentType ?? response.headers.get("content-type") ?? void 0);
|
|
457
|
+
//#endregion
|
|
458
|
+
//#region src/core/attachments/options.ts
|
|
459
|
+
/** Проверяет и дополняет настройки потока. @internal */
|
|
460
|
+
function resolveFileStreamOptions(options, defaultMaxBytes) {
|
|
461
|
+
const mode = options.mode ?? FileTransferMode.Buffer;
|
|
462
|
+
if (mode !== FileTransferMode.Buffer && mode !== FileTransferMode.Stream) throw new require_storage.ItdConfigError(`mode вложения должен быть 'buffer' или 'stream', получено: ${mode}`);
|
|
463
|
+
if (mode === FileTransferMode.Stream && typeof ReadableStream === "undefined") throw new require_storage.ItdConfigError("эта среда не поддерживает ReadableStream; используйте mode: 'buffer'");
|
|
464
|
+
const maxBytes = optionalBytes(options.maxBytes ?? defaultMaxBytes, "maxBytes");
|
|
465
|
+
const streamBufferBytes = optionalBytes(options.streamBufferBytes ?? 4194304, "streamBufferBytes") ?? 4194304;
|
|
466
|
+
if (streamBufferBytes === 0) throw new require_storage.ItdConfigError("streamBufferBytes должен быть больше нуля");
|
|
590
467
|
return {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
...size !== void 0 ? { size } : {},
|
|
595
|
-
close: () => stream.cancel().catch(() => {})
|
|
468
|
+
mode,
|
|
469
|
+
maxBytes,
|
|
470
|
+
streamBufferBytes
|
|
596
471
|
};
|
|
597
472
|
}
|
|
598
|
-
function fromUrl(url, options = {}) {
|
|
599
|
-
if (resolveFileStreamOptions(options, 104857600).mode === FileTransferMode.Stream) return { open: (context) => openUrlFile(url, options, context) };
|
|
600
|
-
return { load: (context) => downloadFile(url, options, context) };
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Создаёт повторяемый пользовательский поток.
|
|
604
|
-
*
|
|
605
|
-
* Фабрика вызывается заново для каждой попытки; возвращать один и тот же поток нельзя.
|
|
606
|
-
*/
|
|
607
|
-
function fromStream(factory, options = {}) {
|
|
608
|
-
const resolved = resolveFileStreamOptions({
|
|
609
|
-
...options,
|
|
610
|
-
mode: FileTransferMode.Stream
|
|
611
|
-
}, void 0);
|
|
612
|
-
optionalBytes(options.size, "size");
|
|
613
|
-
return { open: async (context) => {
|
|
614
|
-
let opened;
|
|
615
|
-
try {
|
|
616
|
-
opened = await factory(context);
|
|
617
|
-
} catch (error) {
|
|
618
|
-
if (error instanceof require_storage.ItdFileError || error instanceof require_storage.ItdConfigError || context.signal?.aborted) throw error;
|
|
619
|
-
throw new require_storage.ItdFileError("не удалось открыть поток вложения", {
|
|
620
|
-
reason: require_storage.ItdFileErrorReason.Read,
|
|
621
|
-
retryable: true,
|
|
622
|
-
cause: error
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
const content = isReadableByteStream(opened) ? { stream: opened } : opened;
|
|
626
|
-
if (!content || !isReadableByteStream(content.stream)) throw new require_storage.ItdConfigError("fromStream должен вернуть ReadableStream или { stream }");
|
|
627
|
-
const size = options.size ?? content.size;
|
|
628
|
-
optionalBytes(size, "size");
|
|
629
|
-
if (resolved.maxBytes !== void 0 && size !== void 0 && size > resolved.maxBytes) {
|
|
630
|
-
await content.close?.();
|
|
631
|
-
throw tooLarge(void 0, resolved.maxBytes, size);
|
|
632
|
-
}
|
|
633
|
-
return {
|
|
634
|
-
stream: boundedFileStream(content.stream, {
|
|
635
|
-
...resolved.maxBytes !== void 0 ? { maxBytes: resolved.maxBytes } : {},
|
|
636
|
-
streamBufferBytes: resolved.streamBufferBytes,
|
|
637
|
-
...context.signal ? { signal: context.signal } : {},
|
|
638
|
-
retryableRead: true
|
|
639
|
-
}),
|
|
640
|
-
...options.filename ?? content.filename ? { filename: options.filename ?? content.filename } : {},
|
|
641
|
-
...normalizeMimeType(options.contentType ?? content.contentType) ? { contentType: normalizeMimeType(options.contentType ?? content.contentType) } : {},
|
|
642
|
-
...size !== void 0 ? { size } : {},
|
|
643
|
-
...content.close ? { close: content.close } : {}
|
|
644
|
-
};
|
|
645
|
-
} };
|
|
646
|
-
}
|
|
647
473
|
//#endregion
|
|
648
474
|
//#region src/core/multi-storage.ts
|
|
649
475
|
/**
|
|
@@ -872,22 +698,10 @@ Object.defineProperty(exports, "createRecordMultiStorage", {
|
|
|
872
698
|
return createRecordMultiStorage;
|
|
873
699
|
}
|
|
874
700
|
});
|
|
875
|
-
Object.defineProperty(exports, "
|
|
876
|
-
enumerable: true,
|
|
877
|
-
get: function() {
|
|
878
|
-
return downloadFile;
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
Object.defineProperty(exports, "fromStream", {
|
|
882
|
-
enumerable: true,
|
|
883
|
-
get: function() {
|
|
884
|
-
return fromStream;
|
|
885
|
-
}
|
|
886
|
-
});
|
|
887
|
-
Object.defineProperty(exports, "fromUrl", {
|
|
701
|
+
Object.defineProperty(exports, "fileTooLarge", {
|
|
888
702
|
enumerable: true,
|
|
889
703
|
get: function() {
|
|
890
|
-
return
|
|
704
|
+
return fileTooLarge;
|
|
891
705
|
}
|
|
892
706
|
});
|
|
893
707
|
Object.defineProperty(exports, "isBoundedFileStream", {
|
|
@@ -896,22 +710,22 @@ Object.defineProperty(exports, "isBoundedFileStream", {
|
|
|
896
710
|
return isBoundedFileStream;
|
|
897
711
|
}
|
|
898
712
|
});
|
|
899
|
-
Object.defineProperty(exports, "
|
|
713
|
+
Object.defineProperty(exports, "isReadableByteStream", {
|
|
900
714
|
enumerable: true,
|
|
901
715
|
get: function() {
|
|
902
|
-
return
|
|
716
|
+
return isReadableByteStream;
|
|
903
717
|
}
|
|
904
718
|
});
|
|
905
|
-
Object.defineProperty(exports, "
|
|
719
|
+
Object.defineProperty(exports, "isRestorableSession", {
|
|
906
720
|
enumerable: true,
|
|
907
721
|
get: function() {
|
|
908
|
-
return
|
|
722
|
+
return isRestorableSession;
|
|
909
723
|
}
|
|
910
724
|
});
|
|
911
|
-
Object.defineProperty(exports, "
|
|
725
|
+
Object.defineProperty(exports, "optionalBytes", {
|
|
912
726
|
enumerable: true,
|
|
913
727
|
get: function() {
|
|
914
|
-
return
|
|
728
|
+
return optionalBytes;
|
|
915
729
|
}
|
|
916
730
|
});
|
|
917
731
|
Object.defineProperty(exports, "resolveFileStreamOptions", {
|
|
@@ -927,4 +741,4 @@ Object.defineProperty(exports, "scopedTokenStorage", {
|
|
|
927
741
|
}
|
|
928
742
|
});
|
|
929
743
|
|
|
930
|
-
//# sourceMappingURL=multi-storage-
|
|
744
|
+
//# sourceMappingURL=multi-storage-C8R5Crwo.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-storage-C8R5Crwo.cjs","names":["#byOrigin","#matching","ItdConfigError","ItdFileError","ItdFileErrorReason","ItdConfigError","ItdFileError","ItdFileErrorReason","ItdConfigError","#sessions","copySession"],"sources":["../node_modules/set-cookie-parser/lib/set-cookie.js","../src/core/cookies.ts","../src/core/attachments/contracts.ts","../src/core/attachments/limits.ts","../src/core/attachments/bounded-stream.ts","../src/core/attachments/options.ts","../src/core/multi-storage.ts"],"sourcesContent":["var defaultParseOptions = {\n decodeValues: true,\n map: false,\n silent: false,\n split: \"auto\", // auto = split strings but not arrays\n};\n\nfunction isForbiddenKey(key) {\n return typeof key !== \"string\" || key in {};\n}\n\nfunction createNullObj() {\n return Object.create(null);\n}\n\nfunction isNonEmptyString(str) {\n return typeof str === \"string\" && !!str.trim();\n}\n\nfunction parseString(setCookieValue, options) {\n var parts = setCookieValue.split(\";\").filter(isNonEmptyString);\n\n var nameValuePairStr = parts.shift();\n if (!nameValuePairStr) {\n return null;\n }\n var parsed = parseNameValuePair(nameValuePairStr);\n var name = parsed.name;\n var value = parsed.value;\n\n options = options\n ? Object.assign({}, defaultParseOptions, options)\n : defaultParseOptions;\n\n if (isForbiddenKey(name)) {\n return null;\n }\n\n try {\n value = options.decodeValues ? decodeURIComponent(value) : value; // decode cookie value\n } catch (e) {\n console.error(\n \"set-cookie-parser: failed to decode cookie value. Set options.decodeValues=false to disable decoding.\",\n e\n );\n }\n\n var cookie = createNullObj();\n cookie.name = name;\n cookie.value = value;\n\n parts.forEach(function (part) {\n var sides = part.split(\"=\");\n var key = sides.shift().trim().toLowerCase();\n if (isForbiddenKey(key)) {\n return;\n }\n var value = sides.join(\"=\").trim();\n if (key === \"expires\") {\n cookie.expires = new Date(value);\n } else if (key === \"max-age\") {\n var n = parseInt(value, 10);\n if (!Number.isNaN(n)) cookie.maxAge = n;\n } else if (key === \"secure\") {\n cookie.secure = true;\n } else if (key === \"httponly\") {\n cookie.httpOnly = true;\n } else if (key === \"samesite\") {\n cookie.sameSite = value;\n } else if (key === \"partitioned\") {\n cookie.partitioned = true;\n } else if (key) {\n cookie[key] = value;\n }\n });\n\n return cookie;\n}\n\nfunction parseNameValuePair(nameValuePairStr) {\n // Parses name-value-pair according to rfc6265bis draft\n\n var name = \"\";\n var value = \"\";\n var nameValueArr = nameValuePairStr.split(\"=\");\n if (nameValueArr.length > 1) {\n name = nameValueArr.shift();\n value = nameValueArr.join(\"=\"); // everything after the first =, joined by a \"=\" if there was more than one part\n } else {\n value = nameValuePairStr;\n }\n\n return { name: name, value: value };\n}\n\nfunction parseSetCookie(input, options) {\n options = options\n ? Object.assign({}, defaultParseOptions, options)\n : defaultParseOptions;\n\n if (!input) {\n if (!options.map) {\n return [];\n } else {\n return createNullObj();\n }\n }\n\n if (input.headers) {\n if (typeof input.headers.getSetCookie === \"function\") {\n // for fetch responses - they combine headers of the same type in the headers array,\n // but getSetCookie returns an uncombined array\n input = input.headers.getSetCookie();\n } else if (input.headers[\"set-cookie\"]) {\n // fast-path for node.js (which automatically normalizes header names to lower-case)\n input = input.headers[\"set-cookie\"];\n } else {\n // slow-path for other environments - see #25\n var sch =\n input.headers[\n Object.keys(input.headers).find(function (key) {\n return key.toLowerCase() === \"set-cookie\";\n })\n ];\n // warn if called on a request-like object with a cookie header rather than a set-cookie header - see #34, 36\n if (!sch && input.headers.cookie && !options.silent) {\n console.warn(\n \"Warning: set-cookie-parser appears to have been called on a request object. It is designed to parse Set-Cookie headers from responses, not Cookie headers from requests. Set the option {silent: true} to suppress this warning.\"\n );\n }\n input = sch;\n }\n }\n\n var split = options.split;\n var isArray = Array.isArray(input);\n\n if (split === \"auto\") {\n split = !isArray;\n }\n\n if (!isArray) {\n input = [input];\n }\n\n input = input.filter(isNonEmptyString);\n\n if (split) {\n input = input.map(splitCookiesString).flat();\n }\n\n if (!options.map) {\n return input\n .map(function (str) {\n return parseString(str, options);\n })\n .filter(Boolean);\n } else {\n var cookies = createNullObj();\n return input.reduce(function (cookies, str) {\n var cookie = parseString(str, options);\n if (cookie && !isForbiddenKey(cookie.name)) {\n cookies[cookie.name] = cookie;\n }\n return cookies;\n }, cookies);\n }\n}\n\n/*\n Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas\n that are within a single set-cookie field-value, such as in the Expires portion.\n\n This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2\n Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128\n React Native's fetch does this for *every* header, including set-cookie.\n\n Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25\n Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation\n*/\nfunction splitCookiesString(cookiesString) {\n if (Array.isArray(cookiesString)) {\n return cookiesString;\n }\n if (typeof cookiesString !== \"string\") {\n return [];\n }\n\n var cookiesStrings = [];\n var pos = 0;\n var start;\n var ch;\n var lastComma;\n var nextStart;\n var cookiesSeparatorFound;\n\n function skipWhitespace() {\n while (pos < cookiesString.length && /\\s/.test(cookiesString.charAt(pos))) {\n pos += 1;\n }\n return pos < cookiesString.length;\n }\n\n function notSpecialChar() {\n ch = cookiesString.charAt(pos);\n\n return ch !== \"=\" && ch !== \";\" && ch !== \",\";\n }\n\n while (pos < cookiesString.length) {\n start = pos;\n cookiesSeparatorFound = false;\n\n while (skipWhitespace()) {\n ch = cookiesString.charAt(pos);\n if (ch === \",\") {\n // ',' is a cookie separator if we have later first '=', not ';' or ','\n lastComma = pos;\n pos += 1;\n\n skipWhitespace();\n nextStart = pos;\n\n while (pos < cookiesString.length && notSpecialChar()) {\n pos += 1;\n }\n\n // currently special character\n if (pos < cookiesString.length && cookiesString.charAt(pos) === \"=\") {\n // we found cookies separator\n cookiesSeparatorFound = true;\n // pos is inside the next cookie, so back up and return it.\n pos = nextStart;\n cookiesStrings.push(cookiesString.substring(start, lastComma));\n start = pos;\n } else {\n // in param ',' or param separator ';',\n // we continue from that comma\n pos = lastComma + 1;\n }\n } else {\n pos += 1;\n }\n }\n\n if (!cookiesSeparatorFound || pos >= cookiesString.length) {\n cookiesStrings.push(cookiesString.substring(start, cookiesString.length));\n }\n }\n\n return cookiesStrings;\n}\n\n// named export for CJS\nparseSetCookie.parseSetCookie = parseSetCookie;\n// for backwards compatibility\nparseSetCookie.parse = parseSetCookie;\nparseSetCookie.parseString = parseString;\nparseSetCookie.splitCookiesString = splitCookiesString;\n\n// EXPORTS\n// (this section is replaced by build-cjs.js)\n\n// named export for ESM\nexport { parseSetCookie };\n// for backwards compatibility\nexport default parseSetCookie;\nexport { parseSetCookie as parse, parseString, splitCookiesString };\n","import { parse as parseSetCookie, splitCookiesString } from 'set-cookie-parser';\n\n/** Cookie, сохранённая в jar. */\ninterface StoredCookie {\n name: string;\n value: string;\n path: string;\n /** Момент истечения, мс с начала эпохи. `undefined` — сессионная cookie. */\n expires: number | undefined;\n secure: boolean;\n}\n\n/** Имя cookie-флага «есть refresh-сессия». Ставится сайтом итд.com рядом с refresh-токеном. */\nexport const AUTH_FLAG_COOKIE = 'is_auth';\n\n/**\n * Имя cookie с refresh-токеном.\n *\n * `POST /api/v1/auth/refresh` читает токен **только отсюда** — тело запроса сервер игнорирует.\n * Cookie помечена `HttpOnly`, поэтому в браузере её не прочитать и не выставить; вне браузера\n * она проходит через jar, и туда же кладётся токен, переданный строкой.\n */\nexport const REFRESH_COOKIE = 'refresh_token';\n\n/** Путь, которым сервер ограничивает {@link REFRESH_COOKIE}. */\nexport const REFRESH_COOKIE_PATH = '/api/v1/auth';\n\n/** Разделитель origin и содержимого cookie при сериализации. В origin пробелов не бывает. */\nconst SERIALIZED_SEPARATOR = ' ';\n\nfunction originOf(url: string): string {\n try {\n return new URL(url).origin;\n } catch {\n return '';\n }\n}\n\n/** Дата в миллисекунды. Некорректная дата считается отсутствующей, а не `NaN`. */\nfunction toTimestamp(date: Date | undefined): number | undefined {\n if (!date) return undefined;\n const time = date.getTime();\n return Number.isFinite(time) ? time : undefined;\n}\n\nfunction pathOf(url: string): string {\n try {\n return new URL(url).pathname || '/';\n } catch {\n return '/';\n }\n}\n\n/**\n * Подходит ли путь cookie запросу.\n *\n * Правило из RFC 6265: путь cookie должен быть префиксом пути запроса, причём граница\n * должна проходить по сегменту — `/api` не подходит запросу `/apiary`.\n */\nfunction pathMatches(cookiePath: string, requestPath: string): boolean {\n if (cookiePath === '/' || cookiePath === requestPath) return true;\n if (!requestPath.startsWith(cookiePath)) return false;\n return cookiePath.endsWith('/') || requestPath[cookiePath.length] === '/';\n}\n\n/**\n * Минимальное хранилище cookie для сред без своего.\n *\n * Refresh-токен итд.com приходит в `Set-Cookie`, а `fetch` вне браузера cookie не хранит —\n * без jar сессию не продлить. В браузере и React Native не используется: там cookie ведёт\n * сама среда.\n *\n * Реализована практическая часть RFC 6265: origin, путь, срок жизни, флаг `Secure`.\n * Доменные cookie для поддоменов намеренно не поддерживаются — API работает с одного хоста.\n */\nexport class CookieJar {\n readonly #byOrigin = new Map<string, Map<string, StoredCookie>>();\n\n /**\n * Забирает `Set-Cookie` из ответа.\n *\n * Использует `Headers.getSetCookie()`, где он есть (Node 20+, undici). В остальных средах\n * заголовки склеены в одну строку, и её нельзя резать по запятой напрямую: запятая есть\n * внутри `Expires=Wed, 09 Jun 2027 …`. Разделением занимается `set-cookie-parser`.\n */\n setFromResponse(url: string, response: Response): void {\n const headers = response.headers as Headers & { getSetCookie?: () => string[] };\n\n const raw =\n typeof headers.getSetCookie === 'function'\n ? headers.getSetCookie()\n : splitCookiesString(headers.get('set-cookie') ?? '');\n\n if (raw.length > 0) this.setFromStrings(url, raw);\n }\n\n /**\n * Кладёт cookie напрямую, минуя `Set-Cookie`.\n *\n * Нужно ровно в одном случае: пользователь передал refresh-токен строкой, а сервер читает\n * его только из cookie. Значение не кодируется — оно уходит в заголовок как есть.\n */\n set(url: string, name: string, value: string, path = '/'): void {\n this.setFromStrings(url, [`${name}=${value}; Path=${path}`]);\n }\n\n /** Сохраняет cookie из готовых строк `Set-Cookie`. */\n setFromStrings(url: string, setCookieStrings: string[]): void {\n const origin = originOf(url);\n if (!origin) return;\n\n const jar = this.#byOrigin.get(origin) ?? new Map<string, StoredCookie>();\n\n for (const parsed of parseSetCookie(setCookieStrings)) {\n // Битую дату (её легко получить, если заголовки склеены неправильно) считаем\n // отсутствующей: сессионная cookie лучше, чем cookie со сроком NaN, которая\n // не истекает и одновременно нигде не находится.\n const expires = toTimestamp(parsed.expires);\n const maxAgeExpires =\n typeof parsed.maxAge === 'number' && Number.isFinite(parsed.maxAge)\n ? Date.now() + parsed.maxAge * 1000\n : undefined;\n\n // Max-Age приоритетнее Expires — так требует RFC 6265.\n const expiresAt = maxAgeExpires ?? expires;\n\n // Удаление cookie сервером: срок в прошлом либо Max-Age=0.\n if (expiresAt !== undefined && expiresAt <= Date.now()) {\n jar.delete(parsed.name);\n continue;\n }\n\n jar.set(parsed.name, {\n name: parsed.name,\n value: parsed.value,\n path: parsed.path ?? '/',\n expires: expiresAt,\n secure: parsed.secure ?? false,\n });\n }\n\n this.#byOrigin.set(origin, jar);\n }\n\n /**\n * Собирает значение заголовка `Cookie` для запроса.\n *\n * @returns строка вида `a=1; b=2` либо `undefined`, если подходящих cookie нет\n */\n getHeader(url: string): string | undefined {\n const cookies = this.#matching(url);\n if (cookies.length === 0) return undefined;\n return cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join('; ');\n }\n\n /**\n * Значение действующей cookie.\n *\n * Нужно, чтобы забрать обновлённый refresh-токен: сервер ротирует его при каждом\n * продлении сессии, и сохранять надо именно новое значение.\n *\n * @param url если указан, учитываются origin, путь и флаг `Secure`\n */\n getValue(name: string, url?: string): string | undefined {\n if (url) return this.#matching(url).find((cookie) => cookie.name === name)?.value;\n\n const now = Date.now();\n for (const jar of this.#byOrigin.values()) {\n const cookie = jar.get(name);\n if (cookie && (cookie.expires === undefined || cookie.expires > now)) return cookie.value;\n }\n return undefined;\n }\n\n /**\n * Есть ли действующая cookie с таким именем.\n *\n * Используется для проверки флага {@link AUTH_FLAG_COOKIE} перед запросом обновления\n * токена: у анонима refresh-сессии нет, и дёргать API незачем.\n */\n has(name: string, url?: string): boolean {\n if (url) return this.#matching(url).some((cookie) => cookie.name === name);\n\n const now = Date.now();\n for (const jar of this.#byOrigin.values()) {\n const cookie = jar.get(name);\n if (cookie && (cookie.expires === undefined || cookie.expires > now)) return true;\n }\n return false;\n }\n\n /** Сохраняет содержимое jar для записи в {@link TokenStorage}. */\n serialize(): string[] {\n const result: string[] = [];\n const now = Date.now();\n\n for (const [origin, jar] of this.#byOrigin) {\n for (const cookie of jar.values()) {\n if (cookie.expires !== undefined && cookie.expires <= now) continue;\n\n const parts = [`${cookie.name}=${cookie.value}`, `Path=${cookie.path}`];\n if (cookie.expires !== undefined) {\n parts.push(`Expires=${new Date(cookie.expires).toUTCString()}`);\n }\n if (cookie.secure) parts.push('Secure');\n\n result.push(`${origin}${SERIALIZED_SEPARATOR}${parts.join('; ')}`);\n }\n }\n\n return result;\n }\n\n /** Восстанавливает jar из результата {@link serialize}. Некорректные записи молча пропускаются. */\n deserialize(entries: readonly string[] | undefined): void {\n if (!entries) return;\n\n for (const entry of entries) {\n const separatorAt = entry.indexOf(SERIALIZED_SEPARATOR);\n if (separatorAt <= 0) continue;\n\n const origin = entry.slice(0, separatorAt);\n const setCookie = entry.slice(separatorAt + 1);\n if (!originOf(origin)) continue;\n\n this.setFromStrings(origin, [setCookie]);\n }\n }\n\n /** Удаляет все cookie. */\n clear(): void {\n this.#byOrigin.clear();\n }\n\n /** Действующие cookie, подходящие запросу: тот же origin, подходящий путь, не истёкшие. */\n #matching(url: string): StoredCookie[] {\n const origin = originOf(url);\n const jar = this.#byOrigin.get(origin);\n if (!jar) return [];\n\n const isSecureRequest = origin.startsWith('https:');\n const requestPath = pathOf(url);\n const now = Date.now();\n const result: StoredCookie[] = [];\n\n for (const cookie of jar.values()) {\n if (cookie.expires !== undefined && cookie.expires <= now) {\n jar.delete(cookie.name);\n continue;\n }\n if (cookie.secure && !isSecureRequest) continue;\n if (!pathMatches(cookie.path, requestPath)) continue;\n\n result.push(cookie);\n }\n\n return result;\n }\n}\n","/** Способ передачи содержимого вложения. */\nexport const FileTransferMode = Object.freeze({\n /** Сначала получить файл целиком, затем отправить его как `Blob`. */\n Buffer: 'buffer',\n /** Передавать данные по мере чтения, не собирая файл целиком в памяти. */\n Stream: 'stream',\n} as const);\nexport type FileTransferMode = (typeof FileTransferMode)[keyof typeof FileTransferMode];\n\n/** Размер очереди потокового вложения по умолчанию — 4 МиБ. */\nexport const DEFAULT_FILE_STREAM_BUFFER_BYTES = 4 * 1024 * 1024;\n\n/** Предел размера файла, скачиваемого по адресу, — 100 МиБ. */\nexport const DEFAULT_URL_FILE_MAX_BYTES = 100 * 1024 * 1024;\n\n/** Что доступно источнику при открытии файла. */\nexport interface FileContext {\n /** Общая отмена текущей попытки, включая её таймаут. */\n signal?: AbortSignal | undefined;\n /** `fetch` клиента — с переданными пользователем настройками. */\n fetch: typeof fetch;\n /** Номер попытки отправки, начиная с 1. */\n attempt: number;\n}\n\n/** Готовое содержимое файла. */\nexport interface FileContent {\n file: Blob | ArrayBuffer | Uint8Array;\n /** Имя влияет на определение MIME, если `contentType` не задан. */\n filename?: string | undefined;\n /** MIME без параметров. Если не указан, определяется по имени или `Blob`. */\n contentType?: string | undefined;\n}\n\n/** Открытый поток файла. */\nexport interface FileStreamContent {\n stream: ReadableStream<Uint8Array>;\n filename?: string | undefined;\n contentType?: string | undefined;\n /** Размер, если он известен до чтения. */\n size?: number | undefined;\n /** Освобождает внешний ресурс после завершения попытки. */\n close?: (() => void | Promise<void>) | undefined;\n}\n\n/** Буферный источник, который вычисляется непосредственно перед первой попыткой. */\nexport interface LazyFile {\n load: (context: FileContext) => FileContent | Promise<FileContent>;\n}\n\n/**\n * Повторяемый потоковый источник.\n *\n * `open` вызывается для каждой попытки отправки. Он обязан возвращать новый поток:\n * уже прочитанный `ReadableStream` повторно использовать нельзя.\n */\nexport interface StreamFile {\n open: (context: FileContext) => FileStreamContent | Promise<FileStreamContent>;\n}\n\n/** Общие настройки потоковой передачи. */\nexport interface FileStreamOptions {\n /** Буферный или потоковый режим. По умолчанию `'buffer'`. */\n mode?: FileTransferMode | undefined;\n /** Максимальный размер файла. Без значения размер не ограничивается. */\n maxBytes?: number | undefined;\n /**\n * Верхняя граница очереди, которой управляет библиотека. По умолчанию 4 МиБ.\n *\n * Сетевой рантайм может иметь собственные внутренние буферы сверх этого значения.\n */\n streamBufferBytes?: number | undefined;\n}\n\n/** Файл, который нужно получить по HTTP(S). */\nexport interface UrlFile extends UrlFileOptions {\n url: string;\n}\n\n/** Настройки файла по HTTP(S). */\nexport interface UrlFileOptions extends FileStreamOptions {\n filename?: string | undefined;\n /** По умолчанию берётся из `Content-Type` ответа. */\n contentType?: string | undefined;\n}\n\n/** Файл для загрузки. Голый поток не принимается, потому что его нельзя повторить. */\nexport type FileInput =\n | Blob\n | ArrayBuffer\n | Uint8Array\n | FileContent\n | UrlFile\n | LazyFile\n | StreamFile;\n\n/** Настройки фабрики пользовательского потока. */\nexport interface FromStreamOptions extends Omit<FileStreamOptions, 'mode'> {\n filename?: string | undefined;\n contentType?: string | undefined;\n /** Размер, если он известен заранее. */\n size?: number | undefined;\n}\n","import { ItdConfigError, ItdFileError, ItdFileErrorReason } from '../errors.js';\n\n/** Проверяет числовую границу до обращения к источнику. */\nexport function optionalBytes(value: number | undefined, name: string): number | undefined {\n if (value === undefined) return undefined;\n if (!Number.isFinite(value) || value < 0 || !Number.isInteger(value)) {\n throw new ItdConfigError(\n `${name} должен быть неотрицательным целым числом, получено: ${value}`,\n );\n }\n return value;\n}\n\n/** Создаёт типизированную ошибку превышения размера вложения. */\nexport function fileTooLarge(url: string | undefined, limit: number, actual: number): ItdFileError {\n const source = url ? ` по адресу ${url}` : '';\n return new ItdFileError(`файл${source} больше предела в ${limit} байт: ${actual}`, {\n reason: ItdFileErrorReason.TooLarge,\n ...(url ? { url } : {}),\n limit,\n actual,\n });\n}\n","import { ItdConfigError, ItdFileError, ItdFileErrorReason } from '../errors.js';\nimport { DEFAULT_FILE_STREAM_BUFFER_BYTES } from './contracts.js';\nimport { fileTooLarge, optionalBytes } from './limits.js';\n\n/** Потоки, на которые уже наложены счётчик размера и backpressure. */\nconst BOUNDED_FILE_STREAMS = new WeakSet<ReadableStream<Uint8Array>>();\n\n/** Настройки ограничивающей поток обёртки. */\nexport interface BoundedFileStreamOptions {\n maxBytes?: number | undefined;\n streamBufferBytes?: number | undefined;\n signal?: AbortSignal | undefined;\n url?: string | undefined;\n retryableRead?: boolean | undefined;\n}\n\n/** Приводит произвольный чанк потока к байтам. */\nfunction asBytes(value: Uint8Array): Uint8Array {\n return value instanceof Uint8Array ? value : new Uint8Array(value);\n}\n\n/** Проверяет значение без обращения к методам потенциально чужого объекта. */\nexport function isReadableByteStream(value: unknown): value is ReadableStream<Uint8Array> {\n return typeof ReadableStream !== 'undefined' && value instanceof ReadableStream;\n}\n\n/**\n * Ограничивает размер и очередь потока. Отмена результирующего потока отменяет исходный.\n *\n * @internal\n */\nexport function boundedFileStream(\n source: ReadableStream<Uint8Array>,\n options: BoundedFileStreamOptions = {},\n): ReadableStream<Uint8Array> {\n const maxBytes = optionalBytes(options.maxBytes, 'maxBytes');\n const streamBufferBytes =\n optionalBytes(\n options.streamBufferBytes ?? DEFAULT_FILE_STREAM_BUFFER_BYTES,\n 'streamBufferBytes',\n ) ?? DEFAULT_FILE_STREAM_BUFFER_BYTES;\n if (streamBufferBytes === 0) {\n throw new ItdConfigError('streamBufferBytes должен быть больше нуля');\n }\n\n const reader = source.getReader();\n let total = 0;\n let finished = false;\n let abortListener: (() => void) | undefined;\n\n const cleanup = () => {\n if (abortListener) options.signal?.removeEventListener('abort', abortListener);\n abortListener = undefined;\n };\n\n const stream = new ReadableStream<Uint8Array>(\n {\n start(controller) {\n if (!options.signal) return;\n abortListener = () => {\n finished = true;\n void reader.cancel(options.signal?.reason).catch(() => {});\n controller.error(options.signal?.reason ?? new DOMException('Aborted', 'AbortError'));\n cleanup();\n };\n if (options.signal.aborted) abortListener();\n else options.signal.addEventListener('abort', abortListener, { once: true });\n },\n async pull(controller) {\n if (finished) return;\n\n try {\n const next = await reader.read();\n if (finished) return;\n if (next.done) {\n finished = true;\n cleanup();\n controller.close();\n return;\n }\n\n const chunk = asBytes(next.value);\n total += chunk.byteLength;\n if (maxBytes !== undefined && total > maxBytes) {\n finished = true;\n await reader.cancel().catch(() => {});\n cleanup();\n controller.error(fileTooLarge(options.url, maxBytes, total));\n return;\n }\n\n controller.enqueue(chunk);\n } catch (error) {\n finished = true;\n cleanup();\n if (error instanceof ItdFileError) {\n controller.error(error);\n return;\n }\n controller.error(\n new ItdFileError('не удалось прочитать поток вложения', {\n reason: ItdFileErrorReason.Read,\n ...(options.url ? { url: options.url } : {}),\n retryable: options.retryableRead ?? false,\n cause: error,\n }),\n );\n }\n },\n async cancel(reason) {\n finished = true;\n cleanup();\n await reader.cancel(reason).catch(() => {});\n },\n },\n {\n highWaterMark: streamBufferBytes,\n size: (chunk) => chunk.byteLength,\n },\n );\n BOUNDED_FILE_STREAMS.add(stream);\n return stream;\n}\n\n/** Наложены ли на поток ограничения библиотеки. @internal */\nexport function isBoundedFileStream(stream: ReadableStream<Uint8Array>): boolean {\n return BOUNDED_FILE_STREAMS.has(stream);\n}\n","import { ItdConfigError } from '../errors.js';\nimport {\n DEFAULT_FILE_STREAM_BUFFER_BYTES,\n type FileStreamOptions,\n FileTransferMode,\n} from './contracts.js';\nimport { optionalBytes } from './limits.js';\n\n/** Проверяет и дополняет настройки потока. @internal */\nexport function resolveFileStreamOptions(\n options: FileStreamOptions,\n defaultMaxBytes?: number,\n): {\n mode: FileTransferMode;\n maxBytes: number | undefined;\n streamBufferBytes: number;\n} {\n const mode = options.mode ?? FileTransferMode.Buffer;\n if (mode !== FileTransferMode.Buffer && mode !== FileTransferMode.Stream) {\n throw new ItdConfigError(`mode вложения должен быть 'buffer' или 'stream', получено: ${mode}`);\n }\n if (mode === FileTransferMode.Stream && typeof ReadableStream === 'undefined') {\n throw new ItdConfigError(\n \"эта среда не поддерживает ReadableStream; используйте mode: 'buffer'\",\n );\n }\n\n const maxBytes = optionalBytes(options.maxBytes ?? defaultMaxBytes, 'maxBytes');\n const streamBufferBytes =\n optionalBytes(\n options.streamBufferBytes ?? DEFAULT_FILE_STREAM_BUFFER_BYTES,\n 'streamBufferBytes',\n ) ?? DEFAULT_FILE_STREAM_BUFFER_BYTES;\n if (streamBufferBytes === 0) {\n throw new ItdConfigError('streamBufferBytes должен быть больше нуля');\n }\n\n return { mode, maxBytes, streamBufferBytes };\n}\n","import { AUTH_FLAG_COOKIE, CookieJar } from './cookies.js';\nimport { copySession, type ItdSession, type TokenStorage } from './storage.js';\n\n/**\n * Хранилище сессий нескольких аккаунтов.\n *\n * Отличается от {@link TokenStorage} тем, что каждый метод получает **имя аккаунта**:\n * так адаптер сам решает, как строить ключ, и Redis, БД или связка ключей получают то,\n * что им нужно. Имя приходит ровно тем, под которым аккаунт заведён в {@link ItdAccounts}:\n * библиотека его не нормализует и не экранирует — префиксы, экранирование и ограничения\n * на длину ключа остаются за адаптером.\n *\n * Все методы могут быть как синхронными, так и асинхронными.\n *\n * @example Своё хранилище поверх Redis\n * ```ts\n * const storage = createMultiTokenStorage({\n * get: async (account) => JSON.parse((await redis.get(`itd:session:${account}`)) ?? 'null'),\n * set: async (account, session) => {\n * await redis.set(`itd:session:${account}`, JSON.stringify(session));\n * await redis.sadd('itd:accounts', account);\n * },\n * clear: async (account) => {\n * await redis.del(`itd:session:${account}`);\n * await redis.srem('itd:accounts', account);\n * },\n * accounts: () => redis.smembers('itd:accounts'),\n * });\n * ```\n */\nexport interface MultiTokenStorage {\n /** Прочитать сессию аккаунта. `null`, если её нет. */\n get(account: string): ItdSession | null | Promise<ItdSession | null>;\n /** Сохранить сессию аккаунта целиком. */\n set(account: string, session: ItdSession): void | Promise<void>;\n /** Удалить сессию аккаунта. Вызывается при выходе и при неудачном обновлении токена. */\n clear(account: string): void | Promise<void>;\n /**\n * Имена сохранённых записей — по ним `ItdAccounts.restore()` находит кандидатов\n * после перезапуска процесса.\n *\n * Список ведёт сам адаптер: у файлового и памятного он виден из самой записи,\n * а хранилищу «ключ — значение» придётся держать множество имён рядом с сессиями.\n * Перед восстановлением контейнер читает каждую запись и пропускает оставшийся после\n * выхода одинокий `deviceId`: без токена или refresh-сессии авторизоваться невозможно.\n * Пустой список означает лишь то, что кандидатов нет, — сами записи при этом могут быть\n * доступны по имени.\n */\n accounts(): readonly string[] | Promise<readonly string[]>;\n}\n\n/**\n * Срез мультихранилища как обычное {@link TokenStorage} — в таком виде его получает\n * отдельный `ItdClient`, который про соседние аккаунты ничего не знает.\n */\nexport function scopedTokenStorage(storage: MultiTokenStorage, account: string): TokenStorage {\n return {\n get: () => storage.get(account),\n set: (session) => storage.set(account, session),\n clear: () => storage.clear(account),\n };\n}\n\n/**\n * Можно ли восстановить авторизованный аккаунт из записи.\n *\n * Один `deviceId` не считается сессией: он намеренно переживает выход, но не позволяет\n * выполнить ни одного авторизованного запроса.\n *\n * @internal\n */\nexport function isRestorableSession(session: ItdSession | null): session is ItdSession {\n if (!session) return false;\n if (session.accessToken || session.refreshToken) return true;\n\n const jar = new CookieJar();\n jar.deserialize(session.cookies);\n return jar.has(AUTH_FLAG_COOKIE);\n}\n\n/**\n * Управляемый срез хранилища для клиента аккаунта.\n *\n * После `revoke()` новые записи не доходят до общего хранилища, а `drain()` позволяет\n * дождаться уже начатых. Так удалённый клиент или завершившийся с опозданием refresh\n * не воскресят сессию после `removeAccount(..., { forget: true })`.\n *\n * @internal\n */\nexport interface ControlledTokenStorage {\n storage: TokenStorage;\n revoke(): void;\n drain(): Promise<void>;\n}\n\n/** @internal */\nexport function controlledTokenStorage(\n storage: MultiTokenStorage,\n account: string,\n): ControlledTokenStorage {\n let revoked = false;\n const pending = new Set<Promise<void>>();\n\n const mutate = (operation: () => void | Promise<void>): Promise<void> => {\n if (revoked) return Promise.resolve();\n\n const promise = Promise.resolve().then(operation);\n pending.add(promise);\n void promise.then(\n () => pending.delete(promise),\n () => pending.delete(promise),\n );\n return promise;\n };\n\n return {\n storage: {\n get: () => (revoked ? null : storage.get(account)),\n set: (session) => mutate(() => storage.set(account, session)),\n clear: () => mutate(() => storage.clear(account)),\n },\n revoke() {\n revoked = true;\n },\n async drain() {\n await Promise.all([...pending]);\n },\n };\n}\n\n/**\n * Мультихранилище в памяти процесса — вариант по умолчанию.\n *\n * Сессии теряются при перезапуске. Для долгоживущих ботов возьмите `FileMultiTokenStorage`\n * из `itd-api/node` либо соберите своё через {@link createMultiTokenStorage}.\n */\nexport class MemoryMultiTokenStorage implements MultiTokenStorage {\n readonly #sessions = new Map<string, ItdSession>();\n\n constructor(initial?: Readonly<Record<string, ItdSession>> | null) {\n for (const [account, session] of Object.entries(initial ?? {})) {\n this.#sessions.set(account, copySession(session));\n }\n }\n\n get(account: string): ItdSession | null {\n const session = this.#sessions.get(account);\n return session ? copySession(session) : null;\n }\n\n set(account: string, session: ItdSession): void {\n this.#sessions.set(account, copySession(session));\n }\n\n clear(account: string): void {\n this.#sessions.delete(account);\n }\n\n accounts(): string[] {\n return [...this.#sessions.keys()];\n }\n}\n\n/**\n * Собирает {@link MultiTokenStorage} из четырёх функций — когда заводить класс избыточно.\n * Аналог `createTokenStorage` для нескольких аккаунтов.\n */\nexport function createMultiTokenStorage(handlers: MultiTokenStorage): MultiTokenStorage {\n return handlers;\n}\n\n/** Источник, который читается и пишется целиком: файл, ключ в `localStorage`, строка в БД. */\nexport interface RecordStorageSource {\n /** Прочитать все сессии разом. `null` — записи ещё нет. */\n read(): Promise<Record<string, ItdSession> | null>;\n /** Записать все сессии разом. */\n write(record: Record<string, ItdSession>): Promise<void>;\n /** Вызывается вместо {@link RecordStorageSource.write}, когда не осталось ни одной сессии. */\n remove?(): Promise<void>;\n}\n\n/** Создаёт запись без прототипа: имена `__proto__` и `constructor` остаются обычными ключами. */\nfunction emptySessionRecord(): Record<string, ItdSession> {\n return Object.create(null) as Record<string, ItdSession>;\n}\n\n/** Копирует внешний снимок в запись без унаследованных свойств. */\nfunction normalizeSessionRecord(\n record: Record<string, ItdSession> | null,\n): Record<string, ItdSession> {\n const normalized = emptySessionRecord();\n for (const [account, session] of Object.entries(record ?? {})) {\n normalized[account] = copySession(session);\n }\n return normalized;\n}\n\n/**\n * Мультихранилище поверх источника, который читается и пишется целиком.\n *\n * Решает главную проблему такого способа хранения — **гонку «прочитать, изменить,\n * записать»**: десять аккаунтов пишут в одну запись, и наивная реализация теряла бы\n * чужие сессии. Источник читается один раз, дальше слепок живёт в памяти, а записи\n * выстраиваются в цепочку и идут по очереди.\n *\n * Внутри процесса этого достаточно. Несколько процессов, пишущих в одну запись,\n * по-прежнему затирают друг друга — как и несколько экземпляров этого адаптера,\n * направленных на один источник в одном процессе.\n */\nexport function createRecordMultiStorage(source: RecordStorageSource): MultiTokenStorage {\n /** Слепок записи. `undefined` — источник ещё не читался. */\n let snapshot: Record<string, ItdSession> | undefined;\n /** Общий промис чтения: параллельные вызовы на холодном старте читают источник один раз. */\n let loading: Promise<Record<string, ItdSession>> | null = null;\n /** Цепочка записей. Ошибка одной не останавливает следующие. */\n let writing: Promise<void> = Promise.resolve();\n\n const load = async (): Promise<Record<string, ItdSession>> => {\n if (snapshot !== undefined) return snapshot;\n\n loading ??= source\n .read()\n .then((value) => {\n snapshot = normalizeSessionRecord(value);\n return snapshot;\n })\n // Сбрасываем и после отказа: иначе одна неудача чтения отравила бы хранилище навсегда.\n .finally(() => {\n loading = null;\n });\n\n return loading;\n };\n\n const flush = (): Promise<void> => {\n // Снимок делается в момент постановки записи в очередь. Иначе следующая мутация\n // общего объекта могла изменить данные операции, которая уже выполняется.\n const current = normalizeSessionRecord(snapshot ?? null);\n\n const operation = async () => {\n // Пустую запись убираем целиком, если источник это умеет: файл с `{}` после выхода\n // из последнего аккаунта выглядел бы мусором.\n if (source.remove && Object.keys(current).length === 0) await source.remove();\n else await source.write(current);\n };\n\n writing = writing.then(operation, operation);\n return writing;\n };\n\n return {\n async get(account) {\n const current = await load();\n const session = Object.hasOwn(current, account) ? current[account] : undefined;\n return session ? copySession(session) : null;\n },\n\n async set(account, session) {\n const current = await load();\n current[account] = copySession(session);\n await flush();\n },\n\n async clear(account) {\n const current = await load();\n if (!Object.hasOwn(current, account)) return;\n\n delete current[account];\n await flush();\n },\n\n async accounts() {\n return Object.keys(await load());\n },\n };\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
|