itd-api 0.4.0 → 0.6.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.
Files changed (42) hide show
  1. package/README.md +6 -4
  2. package/dist/index.cjs +3030 -1579
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +950 -568
  5. package/dist/index.d.ts +950 -568
  6. package/dist/index.js +2961 -1503
  7. package/dist/index.js.map +1 -1
  8. package/dist/{multi-storage-D4h6QA-w.js → multi-storage-BUZaLAPO.js} +132 -84
  9. package/dist/multi-storage-BUZaLAPO.js.map +1 -0
  10. package/dist/{multi-storage-DwaIh24p.d.ts → multi-storage-BUoEoW8f.d.cts} +13 -43
  11. package/dist/{multi-storage-C8R5Crwo.cjs → multi-storage-Bf84xiO8.cjs} +169 -91
  12. package/dist/multi-storage-Bf84xiO8.cjs.map +1 -0
  13. package/dist/{multi-storage-DP_ujJw1.d.cts → multi-storage-CQSlI_kn.d.ts} +13 -43
  14. package/dist/node.cjs +62 -53
  15. package/dist/node.cjs.map +1 -1
  16. package/dist/node.d.cts +19 -5
  17. package/dist/node.d.ts +19 -5
  18. package/dist/node.js +62 -54
  19. package/dist/node.js.map +1 -1
  20. package/dist/storage-BqMxs76Y.d.cts +152 -0
  21. package/dist/storage-BqMxs76Y.d.ts +152 -0
  22. package/dist/{storage-ycBqLBRB.cjs → storage-DnzZPS_9.cjs} +263 -17
  23. package/dist/storage-DnzZPS_9.cjs.map +1 -0
  24. package/dist/{storage-D9tfHx7Z.js → storage-IHdXw52v.js} +210 -18
  25. package/dist/storage-IHdXw52v.js.map +1 -0
  26. package/dist/web.cjs +143 -40
  27. package/dist/web.cjs.map +1 -1
  28. package/dist/web.d.cts +40 -3
  29. package/dist/web.d.ts +40 -3
  30. package/dist/web.js +141 -41
  31. package/dist/web.js.map +1 -1
  32. package/package.json +3 -3
  33. package/dist/multi-storage-C8R5Crwo.cjs.map +0 -1
  34. package/dist/multi-storage-D4h6QA-w.js.map +0 -1
  35. package/dist/runtime-CFEsf-jD.cjs +0 -185
  36. package/dist/runtime-CFEsf-jD.cjs.map +0 -1
  37. package/dist/runtime-DHxDn8gf.js +0 -126
  38. package/dist/runtime-DHxDn8gf.js.map +0 -1
  39. package/dist/storage-BjNRlkbE.d.cts +0 -82
  40. package/dist/storage-BjNRlkbE.d.ts +0 -82
  41. package/dist/storage-D9tfHx7Z.js.map +0 -1
  42. package/dist/storage-ycBqLBRB.cjs.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { i as createTokenStorage, n as MemoryTokenStorage, r as TokenStorage, t as ItdSession } from "./storage-BjNRlkbE.js";
2
- import { _ as StreamFile, a as createRecordMultiStorage, c as DEFAULT_URL_FILE_MAX_BYTES, d as FileInput, f as FileStreamContent, g as LazyFile, h as FromStreamOptions, i as createMultiTokenStorage, l as FileContent, m as FileTransferMode, n as MultiTokenStorage, o as scopedTokenStorage, p as FileStreamOptions, r as RecordStorageSource, s as DEFAULT_FILE_STREAM_BUFFER_BYTES, t as MemoryMultiTokenStorage, u as FileContext, v as UrlFile, y as UrlFileOptions } from "./multi-storage-DwaIh24p.js";
1
+ import { _ as withNamespace, a as createTokenStorage, c as KeyValueStore, d as MemoryKeyValueStore, f as RecordKeyValueStoreSource, g as withCodec, h as isEnumerableKeyValueStore, i as TokenStorageAdapterOptions, l as KeyValueStoreKeys, m as createRecordKeyValueStore, n as MemoryTokenStorage, o as EnumerableKeyValueStore, p as createKeyValueStore, r as TokenStorage, s as KeyValueCodec, t as ItdSession, u as KeyValueStoreResult } from "./storage-BqMxs76Y.js";
2
+ import { a as scopedTokenStorage, c as FileInput, d as FileTransferMode, f as FromStreamOptions, g as UrlFileOptions, h as UrlFile, i as createMultiTokenStorage, l as FileStreamContent, m as StreamFile, n as MultiTokenStorage, o as FileContent, p as LazyFile, r as MultiTokenStorageAdapterOptions, s as FileContext, t as MemoryMultiTokenStorage, u as FileStreamOptions } from "./multi-storage-CQSlI_kn.js";
3
3
  //#region src/types/enums.d.ts
4
4
  /**
5
5
  * Перечисления API итд.com.
@@ -388,6 +388,421 @@ interface ItdClock {
388
388
  /** Системные часы, используемые клиентом по умолчанию. */
389
389
  declare const systemClock: ItdClock;
390
390
  //#endregion
391
+ //#region src/core/operations.d.ts
392
+ /** HTTP-метод встроенной операции. */
393
+ type OperationMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
394
+ /** Семантическая безопасность автоматического повтора операции. */
395
+ declare const RetrySafety: Readonly<{
396
+ /** Автоматический повтор не создаёт неприемлемого эффекта; обычно это чтение. */
397
+ readonly Safe: "safe";
398
+ /** Повтор операции приводит к тому же состоянию, что и один вызов. */
399
+ readonly Idempotent: "idempotent";
400
+ /** Повтор может создать ещё один побочный эффект. */
401
+ readonly Unsafe: "unsafe";
402
+ }>;
403
+ type RetrySafety = (typeof RetrySafety)[keyof typeof RetrySafety];
404
+ /** Минимальное стабильное описание операции, доступное core и плагинам. */
405
+ interface OperationDefinition {
406
+ readonly method: OperationMethod;
407
+ readonly retrySafety: RetrySafety;
408
+ }
409
+ /**
410
+ * Каталог встроенных операций.
411
+ *
412
+ * ID описывает смысл вызова и не меняется при переносе HTTP-пути. Method и retrySafety
413
+ * хранятся здесь, чтобы resources, retry и плагины не вели независимые таблицы операций.
414
+ */
415
+ declare const OPERATIONS: Readonly<{
416
+ readonly 'auth.check': Readonly<{
417
+ readonly method: "GET";
418
+ readonly retrySafety: "safe";
419
+ }>;
420
+ readonly 'auth.signUp': Readonly<{
421
+ readonly method: "POST";
422
+ readonly retrySafety: "unsafe";
423
+ }>;
424
+ readonly 'auth.signIn': Readonly<{
425
+ readonly method: "POST";
426
+ readonly retrySafety: "safe";
427
+ }>;
428
+ readonly 'auth.verifyOtp': Readonly<{
429
+ readonly method: "POST";
430
+ readonly retrySafety: "unsafe";
431
+ }>;
432
+ readonly 'auth.resendOtp': Readonly<{
433
+ readonly method: "POST";
434
+ readonly retrySafety: "unsafe";
435
+ }>;
436
+ readonly 'auth.refresh': Readonly<{
437
+ readonly method: "POST";
438
+ readonly retrySafety: "unsafe";
439
+ }>;
440
+ readonly 'auth.logout': Readonly<{
441
+ readonly method: "POST";
442
+ readonly retrySafety: "unsafe";
443
+ }>;
444
+ readonly 'auth.forgotPassword': Readonly<{
445
+ readonly method: "POST";
446
+ readonly retrySafety: "unsafe";
447
+ }>;
448
+ readonly 'auth.resetPassword': Readonly<{
449
+ readonly method: "POST";
450
+ readonly retrySafety: "unsafe";
451
+ }>;
452
+ readonly 'auth.changePassword': Readonly<{
453
+ readonly method: "POST";
454
+ readonly retrySafety: "unsafe";
455
+ }>;
456
+ readonly 'auth.sessions': Readonly<{
457
+ readonly method: "GET";
458
+ readonly retrySafety: "safe";
459
+ }>;
460
+ readonly 'auth.revokeSession': Readonly<{
461
+ readonly method: "DELETE";
462
+ readonly retrySafety: "unsafe";
463
+ }>;
464
+ readonly 'auth.revokeOtherSessions': Readonly<{
465
+ readonly method: "DELETE";
466
+ readonly retrySafety: "unsafe";
467
+ }>;
468
+ readonly 'users.me': Readonly<{
469
+ readonly method: "GET";
470
+ readonly retrySafety: "safe";
471
+ }>;
472
+ readonly 'users.updateMe': Readonly<{
473
+ readonly method: "PUT";
474
+ readonly retrySafety: "idempotent";
475
+ }>;
476
+ readonly 'users.deactivate': Readonly<{
477
+ readonly method: "DELETE";
478
+ readonly retrySafety: "unsafe";
479
+ }>;
480
+ readonly 'users.restore': Readonly<{
481
+ readonly method: "POST";
482
+ readonly retrySafety: "unsafe";
483
+ }>;
484
+ readonly 'users.createProfile': Readonly<{
485
+ readonly method: "POST";
486
+ readonly retrySafety: "unsafe";
487
+ }>;
488
+ readonly 'users.get': Readonly<{
489
+ readonly method: "GET";
490
+ readonly retrySafety: "safe";
491
+ }>;
492
+ readonly 'users.checkUsername': Readonly<{
493
+ readonly method: "GET";
494
+ readonly retrySafety: "safe";
495
+ }>;
496
+ readonly 'users.search': Readonly<{
497
+ readonly method: "GET";
498
+ readonly retrySafety: "safe";
499
+ }>;
500
+ readonly 'users.whoToFollow': Readonly<{
501
+ readonly method: "GET";
502
+ readonly retrySafety: "safe";
503
+ }>;
504
+ readonly 'users.topClans': Readonly<{
505
+ readonly method: "GET";
506
+ readonly retrySafety: "safe";
507
+ }>;
508
+ readonly 'users.follow': Readonly<{
509
+ readonly method: "POST";
510
+ readonly retrySafety: "unsafe";
511
+ }>;
512
+ readonly 'users.unfollow': Readonly<{
513
+ readonly method: "DELETE";
514
+ readonly retrySafety: "unsafe";
515
+ }>;
516
+ readonly 'users.followers': Readonly<{
517
+ readonly method: "GET";
518
+ readonly retrySafety: "safe";
519
+ }>;
520
+ readonly 'users.following': Readonly<{
521
+ readonly method: "GET";
522
+ readonly retrySafety: "safe";
523
+ }>;
524
+ readonly 'users.followStatus': Readonly<{
525
+ readonly method: "POST";
526
+ readonly retrySafety: "safe";
527
+ }>;
528
+ readonly 'users.block': Readonly<{
529
+ readonly method: "POST";
530
+ readonly retrySafety: "unsafe";
531
+ }>;
532
+ readonly 'users.unblock': Readonly<{
533
+ readonly method: "DELETE";
534
+ readonly retrySafety: "unsafe";
535
+ }>;
536
+ readonly 'users.blocked': Readonly<{
537
+ readonly method: "GET";
538
+ readonly retrySafety: "safe";
539
+ }>;
540
+ readonly 'users.getPrivacy': Readonly<{
541
+ readonly method: "GET";
542
+ readonly retrySafety: "safe";
543
+ }>;
544
+ readonly 'users.updatePrivacy': Readonly<{
545
+ readonly method: "PUT";
546
+ readonly retrySafety: "idempotent";
547
+ }>;
548
+ readonly 'users.pins': Readonly<{
549
+ readonly method: "GET";
550
+ readonly retrySafety: "safe";
551
+ }>;
552
+ readonly 'users.setPin': Readonly<{
553
+ readonly method: "PUT";
554
+ readonly retrySafety: "idempotent";
555
+ }>;
556
+ readonly 'users.removePin': Readonly<{
557
+ readonly method: "DELETE";
558
+ readonly retrySafety: "unsafe";
559
+ }>;
560
+ readonly 'posts.list': Readonly<{
561
+ readonly method: "GET";
562
+ readonly retrySafety: "safe";
563
+ }>;
564
+ readonly 'posts.create': Readonly<{
565
+ readonly method: "POST";
566
+ readonly retrySafety: "unsafe";
567
+ }>;
568
+ readonly 'posts.get': Readonly<{
569
+ readonly method: "GET";
570
+ readonly retrySafety: "safe";
571
+ }>;
572
+ readonly 'posts.update': Readonly<{
573
+ readonly method: "PUT";
574
+ readonly retrySafety: "idempotent";
575
+ }>;
576
+ readonly 'posts.remove': Readonly<{
577
+ readonly method: "DELETE";
578
+ readonly retrySafety: "unsafe";
579
+ }>;
580
+ readonly 'posts.restore': Readonly<{
581
+ readonly method: "POST";
582
+ readonly retrySafety: "unsafe";
583
+ }>;
584
+ readonly 'posts.like': Readonly<{
585
+ readonly method: "POST";
586
+ readonly retrySafety: "unsafe";
587
+ }>;
588
+ readonly 'posts.unlike': Readonly<{
589
+ readonly method: "DELETE";
590
+ readonly retrySafety: "unsafe";
591
+ }>;
592
+ readonly 'posts.repost': Readonly<{
593
+ readonly method: "POST";
594
+ readonly retrySafety: "unsafe";
595
+ }>;
596
+ readonly 'posts.unrepost': Readonly<{
597
+ readonly method: "DELETE";
598
+ readonly retrySafety: "unsafe";
599
+ }>;
600
+ readonly 'posts.pin': Readonly<{
601
+ readonly method: "POST";
602
+ readonly retrySafety: "unsafe";
603
+ }>;
604
+ readonly 'posts.unpin': Readonly<{
605
+ readonly method: "DELETE";
606
+ readonly retrySafety: "unsafe";
607
+ }>;
608
+ readonly 'posts.vote': Readonly<{
609
+ readonly method: "POST";
610
+ readonly retrySafety: "unsafe";
611
+ }>;
612
+ readonly 'posts.stats': Readonly<{
613
+ readonly method: "POST";
614
+ readonly retrySafety: "safe";
615
+ }>;
616
+ readonly 'posts.byUser': Readonly<{
617
+ readonly method: "GET";
618
+ readonly retrySafety: "safe";
619
+ }>;
620
+ readonly 'posts.likedByUser': Readonly<{
621
+ readonly method: "GET";
622
+ readonly retrySafety: "safe";
623
+ }>;
624
+ readonly 'posts.comments': Readonly<{
625
+ readonly method: "GET";
626
+ readonly retrySafety: "safe";
627
+ }>;
628
+ readonly 'posts.comment': Readonly<{
629
+ readonly method: "POST";
630
+ readonly retrySafety: "unsafe";
631
+ }>;
632
+ readonly 'comments.replies': Readonly<{
633
+ readonly method: "GET";
634
+ readonly retrySafety: "safe";
635
+ }>;
636
+ readonly 'comments.reply': Readonly<{
637
+ readonly method: "POST";
638
+ readonly retrySafety: "unsafe";
639
+ }>;
640
+ readonly 'comments.update': Readonly<{
641
+ readonly method: "PATCH";
642
+ readonly retrySafety: "idempotent";
643
+ }>;
644
+ readonly 'comments.remove': Readonly<{
645
+ readonly method: "DELETE";
646
+ readonly retrySafety: "unsafe";
647
+ }>;
648
+ readonly 'comments.restore': Readonly<{
649
+ readonly method: "POST";
650
+ readonly retrySafety: "unsafe";
651
+ }>;
652
+ readonly 'comments.like': Readonly<{
653
+ readonly method: "POST";
654
+ readonly retrySafety: "unsafe";
655
+ }>;
656
+ readonly 'comments.unlike': Readonly<{
657
+ readonly method: "DELETE";
658
+ readonly retrySafety: "unsafe";
659
+ }>;
660
+ readonly 'files.upload': Readonly<{
661
+ readonly method: "POST";
662
+ readonly retrySafety: "unsafe";
663
+ }>;
664
+ readonly 'files.get': Readonly<{
665
+ readonly method: "GET";
666
+ readonly retrySafety: "safe";
667
+ }>;
668
+ readonly 'files.remove': Readonly<{
669
+ readonly method: "DELETE";
670
+ readonly retrySafety: "unsafe";
671
+ }>;
672
+ readonly 'notifications.list': Readonly<{
673
+ readonly method: "GET";
674
+ readonly retrySafety: "safe";
675
+ }>;
676
+ readonly 'notifications.count': Readonly<{
677
+ readonly method: "GET";
678
+ readonly retrySafety: "safe";
679
+ }>;
680
+ readonly 'notifications.markRead': Readonly<{
681
+ readonly method: "POST";
682
+ readonly retrySafety: "idempotent";
683
+ }>;
684
+ readonly 'notifications.markReadBatch': Readonly<{
685
+ readonly method: "POST";
686
+ readonly retrySafety: "idempotent";
687
+ }>;
688
+ readonly 'notifications.markAllRead': Readonly<{
689
+ readonly method: "POST";
690
+ readonly retrySafety: "idempotent";
691
+ }>;
692
+ readonly 'notifications.getSettings': Readonly<{
693
+ readonly method: "GET";
694
+ readonly retrySafety: "safe";
695
+ }>;
696
+ readonly 'notifications.updateSettings': Readonly<{
697
+ readonly method: "PUT";
698
+ readonly retrySafety: "idempotent";
699
+ }>;
700
+ readonly 'realtime.poll.updates': Readonly<{
701
+ readonly method: "GET";
702
+ readonly retrySafety: "safe";
703
+ }>;
704
+ readonly 'realtime.poll.unread': Readonly<{
705
+ readonly method: "GET";
706
+ readonly retrySafety: "safe";
707
+ }>;
708
+ readonly 'hashtags.search': Readonly<{
709
+ readonly method: "GET";
710
+ readonly retrySafety: "safe";
711
+ }>;
712
+ readonly 'hashtags.trending': Readonly<{
713
+ readonly method: "GET";
714
+ readonly retrySafety: "safe";
715
+ }>;
716
+ readonly 'hashtags.posts': Readonly<{
717
+ readonly method: "GET";
718
+ readonly retrySafety: "safe";
719
+ }>;
720
+ readonly 'search.all': Readonly<{
721
+ readonly method: "GET";
722
+ readonly retrySafety: "safe";
723
+ }>;
724
+ readonly 'reports.create': Readonly<{
725
+ readonly method: "POST";
726
+ readonly retrySafety: "unsafe";
727
+ }>;
728
+ readonly 'subscription.status': Readonly<{
729
+ readonly method: "GET";
730
+ readonly retrySafety: "safe";
731
+ }>;
732
+ readonly 'subscription.pay': Readonly<{
733
+ readonly method: "POST";
734
+ readonly retrySafety: "unsafe";
735
+ }>;
736
+ readonly 'subscription.setAutoRenewal': Readonly<{
737
+ readonly method: "POST";
738
+ readonly retrySafety: "idempotent";
739
+ }>;
740
+ readonly 'subscription.bindCard': Readonly<{
741
+ readonly method: "POST";
742
+ readonly retrySafety: "unsafe";
743
+ }>;
744
+ readonly 'subscription.methods': Readonly<{
745
+ readonly method: "GET";
746
+ readonly retrySafety: "safe";
747
+ }>;
748
+ readonly 'subscription.setDefaultMethod': Readonly<{
749
+ readonly method: "POST";
750
+ readonly retrySafety: "idempotent";
751
+ }>;
752
+ readonly 'subscription.removeMethod': Readonly<{
753
+ readonly method: "DELETE";
754
+ readonly retrySafety: "unsafe";
755
+ }>;
756
+ readonly 'verification.status': Readonly<{
757
+ readonly method: "GET";
758
+ readonly retrySafety: "safe";
759
+ }>;
760
+ readonly 'verification.submit': Readonly<{
761
+ readonly method: "POST";
762
+ readonly retrySafety: "unsafe";
763
+ }>;
764
+ readonly 'platform.version': Readonly<{
765
+ readonly method: "GET";
766
+ readonly retrySafety: "safe";
767
+ }>;
768
+ readonly 'platform.changelog': Readonly<{
769
+ readonly method: "GET";
770
+ readonly retrySafety: "safe";
771
+ }>;
772
+ readonly 'platform.announcements': Readonly<{
773
+ readonly method: "GET";
774
+ readonly retrySafety: "safe";
775
+ }>;
776
+ readonly 'platform.portal': Readonly<{
777
+ readonly method: "GET";
778
+ readonly retrySafety: "safe";
779
+ }>;
780
+ readonly 'platform.status': Readonly<{
781
+ readonly method: "GET";
782
+ readonly retrySafety: "safe";
783
+ }>;
784
+ readonly 'telemetry.dwell': Readonly<{
785
+ readonly method: "POST";
786
+ readonly retrySafety: "unsafe";
787
+ }>;
788
+ readonly 'telemetry.interaction': Readonly<{
789
+ readonly method: "POST";
790
+ readonly retrySafety: "unsafe";
791
+ }>;
792
+ }>;
793
+ /** Стабильный ID встроенной операции. */
794
+ type BuiltInOperationId = keyof typeof OPERATIONS;
795
+ /** Пользовательская семантическая операция низкоуровневого запроса. */
796
+ type CustomOperationId = `custom:${string}`;
797
+ /** ID любого запроса, видимый transformers и hooks. */
798
+ type OperationId = BuiltInOperationId | CustomOperationId | 'raw';
799
+ /** Проверяет принадлежность ID встроенному каталогу. */
800
+ declare function isBuiltInOperationId(value: string): value is BuiltInOperationId;
801
+ /** HTTP-метод встроенной операции. */
802
+ declare function operationMethod(id: BuiltInOperationId): OperationMethod;
803
+ /** Политика автоматического повтора встроенной операции. */
804
+ declare function operationRetrySafety(id: BuiltInOperationId): RetrySafety;
805
+ //#endregion
391
806
  //#region src/core/runtime.d.ts
392
807
  /**
393
808
  * Как библиотека обращается с cookie.
@@ -405,14 +820,6 @@ declare const RuntimeMode: Readonly<{
405
820
  readonly Server: "server";
406
821
  }>;
407
822
  type RuntimeMode = (typeof RuntimeMode)[keyof typeof RuntimeMode];
408
- /** Распознанная среда исполнения. */
409
- declare const DetectedRuntime: Readonly<{
410
- readonly Browser: "browser";
411
- /** Есть `window`, но нет `document`; cookie ведёт нативный сетевой слой. */
412
- readonly ReactNative: "react-native";
413
- readonly Server: "server";
414
- }>;
415
- type DetectedRuntime = (typeof DetectedRuntime)[keyof typeof DetectedRuntime];
416
823
  //#endregion
417
824
  //#region src/core/services.d.ts
418
825
  /** Сервис платформы на отдельном домене. */
@@ -431,48 +838,6 @@ interface ServiceDefinition {
431
838
  */
432
839
  auth?: boolean | undefined;
433
840
  }
434
- /**
435
- * Именованные сервисы клиента.
436
- *
437
- * @internal
438
- */
439
- declare class ServiceRegistry {
440
- #private;
441
- /** @param primaryBaseUrl базовый URL клиента */
442
- constructor(primaryBaseUrl?: string);
443
- /**
444
- * Регистрирует сервис. Имя очищается от краевых пробелов, базовый URL приводится
445
- * к каноничному виду, а незаданный `auth` выводится из хоста.
446
- *
447
- * @throws {ItdConfigError} если имя пустое, имя занято или `baseUrl` не абсолютный URL
448
- */
449
- define(definition: ServiceDefinition): void;
450
- /** Определение сервиса либо `undefined`, если такого нет. */
451
- get(name: string): ServiceDefinition | undefined;
452
- /** Зарегистрирован ли сервис с таким именем. */
453
- has(name: string): boolean;
454
- /**
455
- * Определение сервиса.
456
- *
457
- * @throws {ItdConfigError} если сервис не зарегистрирован
458
- */
459
- require(name: string): ServiceDefinition;
460
- /**
461
- * Базовый URL сервиса.
462
- *
463
- * @throws {ItdConfigError} если сервис не зарегистрирован
464
- */
465
- resolveBaseUrl(name: string): string;
466
- /**
467
- * Принадлежит ли URL основному хосту клиента или его поддомену.
468
- *
469
- * Используется для безопасного значения по умолчанию у разового `baseUrl`: Bearer-токен
470
- * не должен уходить на посторонний хост без явного `skipAuth: false`.
471
- *
472
- * @internal
473
- */
474
- isPrimarySite(baseUrl: string): boolean;
475
- }
476
841
  //#endregion
477
842
  //#region src/core/url.d.ts
478
843
  /** Значение параметра запроса. `undefined` и `null` в строку не попадают. */
@@ -538,16 +903,16 @@ interface RetryOptions {
538
903
  maxDelay?: number | undefined;
539
904
  /** Доля случайного разброса паузы, 0…1. По умолчанию 0.3. */
540
905
  jitter?: number | undefined;
541
- /**
542
- * Повторять ли запись (`POST`, `PUT`, `PATCH`, `DELETE`) при сетевых сбоях и `5xx`.
543
- *
544
- * По умолчанию `false`: сервер мог успеть выполнить операцию до обрыва, и повтор
545
- * создаст дубль поста или лишнюю жалобу. Ответ `429` повторяется всегда — он гарантирует,
546
- * что запрос не был обработан.
547
- */
548
- retryWrites?: boolean | undefined;
549
- /** Своя логика: вернуть `true`, чтобы повторить. Заменяет правила по умолчанию. */
550
- shouldRetry?: ((error: unknown, attempt: number) => boolean) | undefined;
906
+ /** Своя логика: вернуть `true`, чтобы повторить. Заменяет семантическое правило операции. */
907
+ shouldRetry?: ((error: unknown, attempt: number, context: RetryDecisionContext) => boolean) | undefined;
908
+ }
909
+ /** Семантика запроса, доступная пользовательской функции `shouldRetry`. */
910
+ interface RetryDecisionContext {
911
+ operationId: OperationId;
912
+ retrySafety: RetrySafety;
913
+ bodyReplayable: boolean;
914
+ method: string;
915
+ path: string;
551
916
  }
552
917
  /** Настройки ограничения нагрузки на API. */
553
918
  interface RateLimitOptions {
@@ -577,6 +942,8 @@ interface RateLimitOptions {
577
942
  }
578
943
  /** Данные о запросе, доступные хукам. */
579
944
  interface RequestContext {
945
+ /** Стабильная семантическая операция; `raw` у низкоуровневого вызова без явного ID. */
946
+ operationId: OperationId;
580
947
  method: string;
581
948
  /** Путь без базового URL, например `/api/posts`. */
582
949
  path: string;
@@ -591,6 +958,7 @@ interface ResponseContext extends RequestContext {
591
958
  status: number;
592
959
  /** Длительность запроса в мс. */
593
960
  duration: number;
961
+ /** Отдельная копия ответа: её тело можно прочитать, не мешая разбору внутри SDK. */
594
962
  response: Response;
595
963
  }
596
964
  /** Данные об ошибке запроса. */
@@ -638,7 +1006,10 @@ interface ItdClientOptions {
638
1006
  * Сервисы платформы на отдельных доменах.
639
1007
  *
640
1008
  * Ключ — имя сервиса, значение — базовый URL или определение целиком. Имя встроенного
641
- * сервиса задаёт его хост. Встроен один: `status` хост `itd.platform.status()`.
1009
+ * сервиса задаёт его хост; встроен один — `status`.
1010
+ *
1011
+ * `auth` у встроенного сервиса наследуется, у нового выводится по хосту: токен уходит
1012
+ * основному хосту и его поддоменам, остальным — по явному `auth: true`.
642
1013
  *
643
1014
  * @example
644
1015
  * ```ts
@@ -674,6 +1045,14 @@ interface ItdClientOptions {
674
1045
  clock?: ItdClock | undefined;
675
1046
  /** Таймаут запроса в мс. По умолчанию 30000 — столько же использует сайт итд.com. `0` снимает ограничение. */
676
1047
  timeout?: number | undefined;
1048
+ /**
1049
+ * Сколько `close()` и `dispose()` ждут чужой код, мс. По умолчанию 10000.
1050
+ *
1051
+ * Ждут обработчиков realtime-потока и операций, вошедших в обёртки плагинов. По истечении
1052
+ * срока ресурсы всё равно освобождаются, а метод отклоняется `ItdStateError` с указанием
1053
+ * того, что удерживало остановку. `0` снимает ограничение.
1054
+ */
1055
+ shutdownTimeout?: number | undefined;
677
1056
  /** Повторные попытки. `false` отключает их полностью. */
678
1057
  retry?: RetryOptions | false | undefined;
679
1058
  /** Ограничение нагрузки. `false` отключает очередь. */
@@ -703,7 +1082,14 @@ interface ItdClientOptions {
703
1082
  /** Как обращаться с cookie. По умолчанию определяется по среде исполнения. */
704
1083
  mode?: RuntimeMode | undefined;
705
1084
  }
706
- /** Опции отдельного запроса. Доступны в каждом методе ресурсов. */
1085
+ /**
1086
+ * Namespaces расширений отдельной операции.
1087
+ *
1088
+ * Пакеты дополняют интерфейс через declaration merging и владеют только своим полем.
1089
+ * Core передаёт объект operation transformers без знания его содержимого.
1090
+ */
1091
+ interface RequestExtensions {}
1092
+ /** Опции выполнения отдельного запроса. Передаются последним аргументом методов ресурсов. */
707
1093
  interface RequestOptions {
708
1094
  /** Отмена запроса извне. */
709
1095
  signal?: AbortSignal | undefined;
@@ -713,23 +1099,28 @@ interface RequestOptions {
713
1099
  headers?: Record<string, string> | undefined;
714
1100
  /** Повторы только для этого запроса. Переопределяют глобальную настройку `retry`. */
715
1101
  retry?: RetryOptions | false | undefined;
1102
+ /**
1103
+ * Явно переопределяет безопасность повтора операции.
1104
+ *
1105
+ * Встроенные resources получают значение из каталога. Опция нужна прежде всего custom/raw
1106
+ * интеграциям и осознанному переопределению серверного контракта.
1107
+ */
1108
+ retrySafety?: RetrySafety | undefined;
1109
+ /** Настройки подключённых operation extensions, сгруппированные по владельцу. */
1110
+ extensions?: RequestExtensions | undefined;
1111
+ }
1112
+ /** Опции перебора страниц, не являющиеся параметрами endpoint. */
1113
+ interface PaginationOptions extends RequestOptions {
1114
+ /** Максимальное число страниц; без значения перебор продолжается до конца списка. */
1115
+ maxPages?: number | undefined;
716
1116
  }
717
- /**
718
- * Имена полей {@link RequestOptions} — единственный источник истины.
719
- *
720
- * Ресурсы переносят в описание запроса только эти поля (плюс заявленные плагинами),
721
- * потому что параметры методов подмешивают к ним `limit`, `cursor` и прочее, чему
722
- * в транспорте делать нечего. Список стоит рядом с интерфейсом, чтобы новое поле нельзя
723
- * было забыть.
724
- *
725
- * `satisfies` гарантирует, что каждое имя в списке — действительно поле `RequestOptions`.
726
- * Обратную полноту (не забыто ли новое поле) проверяет тип {@link RequestOptionKeysComplete}
727
- * в тесте: здесь её проверять нельзя — плагины расширяют `RequestOptions` своими опциями
728
- * (`encrypt`, `decrypt` и подобными), которых в этом списке быть и не должно.
729
- */
730
- declare const REQUEST_OPTION_KEYS: readonly ["signal", "timeout", "headers", "retry"];
731
1117
  /** Полное описание запроса для низкоуровневого `itd.request()`. */
732
1118
  interface RawRequestOptions extends RequestOptions {
1119
+ /**
1120
+ * Семантическое имя низкоуровневого запроса. Встроенные resources выставляют его сами.
1121
+ * Пользовательские значения следует помещать в namespace `custom:`.
1122
+ */
1123
+ operationId?: OperationId | undefined;
733
1124
  method: string;
734
1125
  /** Путь с ведущим слэшем, например `/api/posts`. Завершающий слэш значим. */
735
1126
  path: string;
@@ -760,48 +1151,27 @@ interface RawRequestOptions extends RequestOptions {
760
1151
  /**
761
1152
  * Выполнить запрос мимо очереди.
762
1153
  *
763
- * Нужно запросам, которые слой авторизации делает **изнутри** другого запроса: продление
764
- * токена и отложенный вход. Такой запрос обязан стартовать, пока исходный держит место
765
- * в очереди и ждёт его результата, — иначе оба ждут друг друга и не завершатся никогда.
1154
+ * Продвинутый escape hatch для служебных интеграций. Встроенные refresh и sign-in проходят
1155
+ * обычную очередь: она охватывает только одну сетевую попытку и не создаёт deadlock.
766
1156
  */
767
1157
  skipQueue?: boolean | undefined;
768
1158
  /** Вернуть тело ответа без снятия обёртки `{ data: … }`. */
769
1159
  raw?: boolean | undefined;
770
1160
  }
1161
+ /** Запрос внутри pipeline: в отличие от raw input всегда имеет семантический ID. */
1162
+ interface OperationRequestOptions extends RawRequestOptions {
1163
+ operationId: OperationId;
1164
+ }
771
1165
  //#endregion
772
1166
  //#region src/core/version.d.ts
773
1167
  /** Версия библиотеки. Попадает в `User-Agent`. */
774
- declare const LIBRARY_VERSION = "0.4.0";
1168
+ declare const LIBRARY_VERSION = "0.6.0";
775
1169
  //#endregion
776
1170
  //#region src/core/config.d.ts
777
1171
  /** Базовый URL API итд.com. Домен записан в punycode: `итд.com`. */
778
1172
  declare const DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
779
- /** Базовый URL страницы статуса. Домен записан в punycode: `статус.итд.com`. */
780
- declare const DEFAULT_STATUS_BASE_URL = "https://xn--80a7abcbg.xn--d1ah4a.com";
781
1173
  /** Имя встроенного сервиса статуса. */
782
1174
  declare const STATUS_SERVICE = "status";
783
- /** Сервисы, зарегистрированные у любого клиента. */
784
- declare const BUILT_IN_SERVICES: readonly ServiceDefinition[];
785
- /** Таймаут запроса по умолчанию — 30 секунд. */
786
- declare const DEFAULT_TIMEOUT = 30000;
787
- /**
788
- * `User-Agent` по умолчанию.
789
- *
790
- * Сайт стоит за DDoS-Guard, и запросы вовсе без `User-Agent` (так делает `fetch` в Node)
791
- * имеют шанс не пройти фильтр. Префикс `Mozilla/5.0` — дань традиции таких фильтров,
792
- * дальше идёт честное имя библиотеки: подделываться под браузер она не должна.
793
- *
794
- * В браузере заголовок не выставляется — `User-Agent` там запрещён к изменению, и среда
795
- * молча его игнорирует.
796
- */
797
- declare const DEFAULT_USER_AGENT = "Mozilla/5.0 (compatible; itd-api/0.4.0; +https://github.com/KiowDev/itd-api)";
798
- /** Настройки очереди со всеми значениями по умолчанию. */
799
- interface ResolvedRateLimitOptions {
800
- concurrency: number;
801
- rps: number | undefined;
802
- retryDelays: readonly number[];
803
- respectHeaders: boolean;
804
- }
805
1175
  /**
806
1176
  * Срез конфигурации, нужный слою авторизации.
807
1177
  *
@@ -821,18 +1191,6 @@ interface AuthConfig {
821
1191
  }
822
1192
  //#endregion
823
1193
  //#region src/core/cookies.d.ts
824
- /** Имя cookie-флага «есть refresh-сессия». Ставится сайтом итд.com рядом с refresh-токеном. */
825
- declare const AUTH_FLAG_COOKIE = "is_auth";
826
- /**
827
- * Имя cookie с refresh-токеном.
828
- *
829
- * `POST /api/v1/auth/refresh` читает токен **только отсюда** — тело запроса сервер игнорирует.
830
- * Cookie помечена `HttpOnly`, поэтому в браузере её не прочитать и не выставить; вне браузера
831
- * она проходит через jar, и туда же кладётся токен, переданный строкой.
832
- */
833
- declare const REFRESH_COOKIE = "refresh_token";
834
- /** Путь, которым сервер ограничивает {@link REFRESH_COOKIE}. */
835
- declare const REFRESH_COOKIE_PATH = "/api/v1/auth";
836
1194
  /**
837
1195
  * Минимальное хранилище cookie для сред без своего.
838
1196
  *
@@ -959,15 +1317,9 @@ type RequestBodyFactory = (context: RequestBodyContext) => PreparedRequestBody |
959
1317
  * важнее. Смешивать их в одном объекте нельзя — тогда слой авторизации перебивал бы
960
1318
  * `Authorization`, заданный вызывающим кодом вручную.
961
1319
  */
962
- interface PipelineRequest extends RawRequestOptions {
1320
+ interface PipelineRequest extends OperationRequestOptions {
963
1321
  /** Повторяемое тело. Используется внутренними ресурсами вместо `body`. @internal */
964
1322
  bodyFactory?: RequestBodyFactory | undefined;
965
- /**
966
- * Разрешает повтор записи после сетевого сбоя. Тело должно быть повторяемым.
967
- *
968
- * @internal
969
- */
970
- retryNetworkWrite?: boolean | undefined;
971
1323
  /**
972
1324
  * Заголовки, добавленные слоями конвейера.
973
1325
  *
@@ -977,35 +1329,31 @@ interface PipelineRequest extends RawRequestOptions {
977
1329
  */
978
1330
  layerHeaders?: Record<string, string> | undefined;
979
1331
  /**
980
- * Номер попытки, начиная с 1. Проставляет слой повторов, читают хуки.
1332
+ * Номер фактически начатой транспортной попытки, начиная с 1. Проставляет attempt layer.
981
1333
  *
982
1334
  * @internal
983
1335
  */
984
1336
  attempt?: number | undefined;
985
1337
  }
1338
+ /** Запрос на внешней границе pipeline. Низкоуровневый вызов без ID считается `raw`. */
1339
+ type PipelineRequestInput = Omit<PipelineRequest, 'operationId'> & {
1340
+ operationId?: OperationId | undefined;
1341
+ };
986
1342
  /** Обработчик запроса. Самый внутренний в цепочке — транспорт. */
987
1343
  type RequestHandler = (request: PipelineRequest) => Promise<unknown>;
988
1344
  //#endregion
989
1345
  //#region src/core/auth.d.ts
990
- /** Пути эндпоинтов авторизации. */
991
- declare const AUTH_PATHS: {
992
- readonly signUp: "/api/v1/auth/sign-up";
993
- readonly signIn: "/api/v1/auth/sign-in";
994
- readonly verifyOtp: "/api/v1/auth/verify-otp";
995
- readonly resendOtp: "/api/v1/auth/resend-otp";
996
- readonly refresh: "/api/v1/auth/refresh";
997
- readonly logout: "/api/v1/auth/logout";
998
- readonly forgotPassword: "/api/v1/auth/forgot-password";
999
- readonly resetPassword: "/api/v1/auth/reset-password";
1000
- readonly changePassword: "/api/v1/auth/change-password";
1001
- readonly sessions: "/api/v1/auth/sessions";
1002
- };
1003
1346
  /**
1004
1347
  * Публичный ключ Cloudflare Turnstile платформы итд.com.
1005
1348
  *
1006
1349
  * Нужен, чтобы отрисовать виджет капчи и получить токен для `signIn`, `signUp`
1007
1350
  * и `forgotPassword`.
1008
1351
  *
1352
+ * Ключ привязан к домену: на чужом origin Cloudflare отказывает виджету с кодом `110200`.
1353
+ * Поэтому отрисовать его может только код, выполняемый на самом итд.com. Остальным
1354
+ * подходит `@itd-api/turnstile`, готовый токен из другого источника или вовсе вход
1355
+ * без капчи — по сохранённой сессии либо по токенам, взятым в браузере.
1356
+ *
1009
1357
  * @example
1010
1358
  * ```ts
1011
1359
  * turnstile.render('#captcha', {
@@ -1015,8 +1363,6 @@ declare const AUTH_PATHS: {
1015
1363
  * ```
1016
1364
  */
1017
1365
  declare const TURNSTILE_SITE_KEY = "0x4AAAAAACHhxczw6fJGwPBg";
1018
- /** Заголовок с идентификатором устройства. Сервер связывает с ним запись в списке сессий. */
1019
- declare const DEVICE_ID_HEADER = "X-Device-Id";
1020
1366
  /** События слоя авторизации. */
1021
1367
  interface AuthEvents {
1022
1368
  /** Токен получен или обновлён. */
@@ -1060,6 +1406,8 @@ declare class AuthManager {
1060
1406
  get on(): Emitter<AuthEvents>['on'];
1061
1407
  /** Подписка на одно срабатывание. */
1062
1408
  get once(): Emitter<AuthEvents>['once'];
1409
+ /** Снимает lifecycle-подписки при терминальном освобождении владельца. @internal */
1410
+ dispose(): void;
1063
1411
  /**
1064
1412
  * Непрозрачная fallback-область авторизации.
1065
1413
  *
@@ -1084,6 +1432,15 @@ declare class AuthManager {
1084
1432
  hasRefreshSession(): Promise<boolean>;
1085
1433
  /** Заголовки авторизации для очередного запроса. Пустой объект, если токена нет. */
1086
1434
  getAuthHeaders(): Promise<Record<string, string>>;
1435
+ /**
1436
+ * Заголовки уже подготовленной авторизации без чтения storage или вызова внешнего источника.
1437
+ *
1438
+ * Используются после ожидания транспортной очереди: к этому моменту `getAccessToken()` уже
1439
+ * был вызван снаружи неё, но token мог успеть смениться из-за refresh или `setSession()`.
1440
+ *
1441
+ * @internal
1442
+ */
1443
+ getCurrentAuthHeaders(): Record<string, string>;
1087
1444
  /**
1088
1445
  * Идентификатор устройства для заголовка `X-Device-Id`.
1089
1446
  *
@@ -1137,30 +1494,102 @@ declare class AuthManager {
1137
1494
  //#endregion
1138
1495
  //#region src/core/plugins/contracts.d.ts
1139
1496
  /**
1140
- * Обёртка вокруг запроса.
1497
+ * Обёртка одной логической операции.
1141
1498
  *
1142
- * Получает описание запроса и продолжение цепочки. Может изменить запрос перед отправкой,
1143
- * посмотреть и подменить разобранный ответ или вовсе не вызывать `next` и вернуть своё.
1499
+ * Вызывается ровно один раз независимо от retry и auth recovery. Может изменить
1500
+ * семантический запрос, обработать разобранный результат или завершить операцию локально.
1144
1501
  *
1145
- * @param request что уходит на сервер; изменять сам объект не нужно — передайте копию в `next`
1146
- * @param next продолжение: либо следующая обёртка, либо настоящий запрос
1147
- * @returns тело ответа в том виде, в каком его получит вызывающий код
1502
+ * @param request описание логической операции; не изменяйте сам объект — передайте копию в `next`
1503
+ * @param next следующая обёртка либо выполнение операции
1504
+ * @returns разобранный результат в том виде, в котором его получит вызывающий код
1148
1505
  *
1149
- * @example Дописать заголовок ко всем запросам
1506
+ * @example Дописать заголовок ко всем операциям
1150
1507
  * ```ts
1151
- * const transformer: Transformer = (request, next) =>
1508
+ * const transformer: OperationTransformer = (request, next) =>
1152
1509
  * next({ ...request, headers: { ...request.headers, 'X-Trace': trace() } });
1153
1510
  * ```
1154
1511
  */
1155
- type Transformer = (request: RawRequestOptions, next: (request: RawRequestOptions) => Promise<unknown>) => Promise<unknown>;
1156
- /** Освобождение ресурсов, заведённых плагином при установке. */
1512
+ type OperationTransformer = (request: OperationRequestOptions, next: (request: OperationRequestOptions) => Promise<unknown>) => Promise<unknown>;
1513
+ /** Финальные данные одной транспортной попытки. */
1514
+ interface AttemptContext {
1515
+ /** Стабильная семантическая операция. */
1516
+ readonly operationId: OperationId;
1517
+ /** Нормализованный HTTP-метод. */
1518
+ readonly method: string;
1519
+ /** Исходный путь операции до разрешения service/base URL. */
1520
+ readonly path: string;
1521
+ /** Полностью разрешённый URL со строкой query. */
1522
+ readonly url: string;
1523
+ /** Итоговые заголовки. Сам объект mutable для подписи и diagnostic headers. */
1524
+ readonly headers: Headers;
1525
+ /** Номер transport attempt, начиная с 1. */
1526
+ readonly attempt: number;
1527
+ /** Тело после сериализации либо подготовки body factory. Поток нельзя читать заранее. */
1528
+ readonly body: BodyInit | undefined;
1529
+ /** Общий сигнал отмены и таймаута этой попытки. */
1530
+ readonly signal: AbortSignal;
1531
+ }
1532
+ /**
1533
+ * Продолжение attempt chain.
1534
+ *
1535
+ * В рамках одного interceptor его можно вызвать только один раз. Возвращает сырой ответ:
1536
+ * transport ещё не проверял status и не читал body.
1537
+ */
1538
+ type AttemptNext = () => Promise<Response>;
1539
+ /**
1540
+ * Обёртка одной транспортной попытки.
1541
+ *
1542
+ * Получает уже разрешённый URL, итоговые заголовки, подготовленное тело и номер попытки.
1543
+ * Может дописать заголовки, измерить wire latency, обработать сырой `Response` или вернуть
1544
+ * синтетический `Response`. Семантический input здесь намеренно недоступен для изменения.
1545
+ *
1546
+ * Вызывается заново для каждого retry и auth recovery. `next()` разрешено вызвать один раз.
1547
+ * Если interceptor читает тело ответа, читать нужно `response.clone()`: исходный body после
1548
+ * цепочки разбирает transport. Исключение interceptor остаётся пользовательской ошибкой и не
1549
+ * классифицируется как сетевой сбой для автоматического retry.
1550
+ *
1551
+ * @param context окончательные данные текущей транспортной попытки
1552
+ * @param next следующий interceptor либо вызов `fetch`
1553
+ * @returns исходный или синтетический сырой `Response`
1554
+ */
1555
+ type AttemptInterceptor = (context: AttemptContext, next: AttemptNext) => Promise<Response>;
1556
+ /** Регистрация расширений логической операции. */
1557
+ interface OperationExtensions {
1558
+ /**
1559
+ * Подключает transformer.
1560
+ *
1561
+ * Зарегистрированные раньше оборачивают зарегистрированные позже. Возвращённая функция
1562
+ * идемпотентна и снимает только эту регистрацию.
1563
+ */
1564
+ use(transformer: OperationTransformer): Unsubscribe;
1565
+ }
1566
+ /** Регистрация расширений транспортной попытки. */
1567
+ interface AttemptExtensions {
1568
+ /**
1569
+ * Подключает interceptor.
1570
+ *
1571
+ * Зарегистрированные раньше оборачивают зарегистрированные позже. Возвращённая функция
1572
+ * идемпотентна и снимает только эту регистрацию.
1573
+ */
1574
+ use(interceptor: AttemptInterceptor): Unsubscribe;
1575
+ }
1576
+ /**
1577
+ * Освобождение ресурсов, заведённых плагином при установке.
1578
+ *
1579
+ * Вызывается после завершения логических операций, уже вошедших в расширения плагина,
1580
+ * поэтому может безопасно закрывать используемые ими соединения и хранилища.
1581
+ */
1157
1582
  type PluginTeardown = () => void | Promise<void>;
1158
- /** Что плагин получает при подключении. */
1159
- interface PluginContext {
1583
+ /** API, доступный плагину при подключении. */
1584
+ interface PluginApi {
1160
1585
  /** Базовый URL клиента — например чтобы разобрать абсолютные ссылки из ответа. */
1161
1586
  baseUrl: string;
1162
1587
  /** Отладочный вывод клиента, если он включён. */
1163
1588
  logger: Logger | undefined;
1589
+ /** Расширения логической операции: выполняются один раз и могут short-circuit сеть. */
1590
+ operations: OperationExtensions;
1591
+ /** Расширения wire attempt: выполняются заново после каждого retry/auth recovery. */
1592
+ attempts: AttemptExtensions;
1164
1593
  /**
1165
1594
  * Непрозрачная fallback-область текущей авторизации.
1166
1595
  *
@@ -1175,29 +1604,25 @@ interface PluginContext {
1175
1604
  * несколькими экземплярами клиента одного аккаунта.
1176
1605
  */
1177
1606
  getAuthIdentity?: (() => Promise<AuthIdentity>) | undefined;
1178
- /** Добавляет обёртку запроса. Подключённые раньше оказываются снаружи. */
1179
- use(transformer: Transformer): void;
1180
- /**
1181
- * Добавляет перехватчики отдельных сетевых попыток.
1182
- *
1183
- * В отличие от {@link use}, они видят каждый retry и сырой `Response` до чтения тела.
1184
- * Несколько наборов хуков одного плагина вызываются в порядке регистрации.
1185
- */
1186
- useHooks(hooks: ClientHooks): void;
1187
1607
  }
1188
1608
  /**
1189
1609
  * Плагин клиента.
1190
1610
  *
1191
- * Подключается через `itd.use(plugin)` и работает на уровне транспорта: видит запрос
1192
- * до отправки и разобранный ответ. Библиотека не знает, что именно делает плагин, —
1193
- * ей достаточно списка обёрток и имён опций, которые он читает.
1611
+ * Подключается через `itd.use(plugin)` и регистрирует расширения одного или обоих уровней:
1612
+ * {@link OperationTransformer} для логической операции и {@link AttemptInterceptor} для
1613
+ * отдельной транспортной попытки. Core взаимодействует с плагином только через эти контракты
1614
+ * и его lifecycle, не зная деталей реализации.
1194
1615
  *
1195
- * @example
1616
+ * Настройки отдельного вызова плагин объявляет своим полем в `RequestExtensions` через
1617
+ * declaration merging. Пользователь передаёт их в `RequestOptions.extensions`, а operation
1618
+ * transformer читает только принадлежащий плагину namespace.
1619
+ *
1620
+ * @example Логирование логических операций
1196
1621
  * ```ts
1197
- * const logging: ItdPlugin = {
1622
+ * const logging: ClientPlugin = {
1198
1623
  * name: 'logging',
1199
- * install({ use, logger }) {
1200
- * use(async (request, next) => {
1624
+ * install({ operations, logger }) {
1625
+ * operations.use(async (request, next) => {
1201
1626
  * logger?.info(`${request.method} ${request.path}`);
1202
1627
  * return next(request);
1203
1628
  * });
@@ -1207,94 +1632,25 @@ interface PluginContext {
1207
1632
  * itd.use(logging);
1208
1633
  * ```
1209
1634
  */
1210
- interface ItdPlugin {
1635
+ interface ClientPlugin {
1211
1636
  /** Имя плагина. Должно быть уникальным: повторное подключение — ошибка. */
1212
1637
  name: string;
1213
- /**
1214
- * Имена опций запроса, которые плагин читает у методов ресурсов.
1215
- *
1216
- * Библиотека этих опций не понимает и ничего с ними не делает — только доносит
1217
- * от вызова метода до обёртки нетронутыми. Без такого списка чужие поля отсеиваются,
1218
- * чтобы случайная опечатка в параметрах не уезжала на сервер.
1219
- *
1220
- * Имена полей самого запроса (`path`, `body`, `headers`, `signal` и прочие из
1221
- * `RawRequestOptions`) заявить нельзя: подключение такого плагина завершится ошибкой.
1222
- *
1223
- * Типы для них плагин объявляет сам, дополняя `RequestOptions`:
1224
- * ```ts
1225
- * declare module 'itd-api' {
1226
- * interface RequestOptions { encrypt?: string | undefined }
1227
- * }
1228
- * ```
1229
- */
1230
- optionKeys?: readonly string[];
1231
1638
  /** Плагины, которые обязаны быть подключены раньше этого. */
1232
1639
  requires?: readonly string[];
1233
1640
  /** Несовместимые плагины. Достаточно объявить конфликт с одной стороны. */
1234
1641
  conflicts?: readonly string[];
1235
- /** Имена плагинов, снаружи которых должна стоять эта обёртка. */
1642
+ /** Имена плагинов, снаружи которых должны стоять оба вида расширений этого плагина. */
1236
1643
  before?: readonly string[];
1237
- /** Имена плагинов, внутри которых должна стоять эта обёртка. */
1644
+ /** Имена плагинов, внутри которых должны стоять оба вида расширений этого плагина. */
1238
1645
  after?: readonly string[];
1239
1646
  /**
1240
1647
  * Устанавливает плагин.
1241
1648
  *
1242
1649
  * Может вернуть функцию освобождения ресурсов. Она вызывается при `unuse()` или
1243
- * окончательном `dispose()` клиента и может быть асинхронной.
1244
- */
1245
- install(context: PluginContext): unknown;
1246
- }
1247
- //#endregion
1248
- //#region src/core/rate-limit.d.ts
1249
- /**
1250
- * Очередь запросов: ограничивает одновременность и частоту.
1251
- *
1252
- * Нужна прежде всего ботам: без неё цикл по сотне постов уходит в API одним залпом
1253
- * и упирается в `RATE_LIMIT_EXCEEDED`.
1254
- *
1255
- * Частота выдерживается равномерным разносом стартов (`1000 / rps` между запросами),
1256
- * а не окном со счётчиком: так нагрузка ровная, без всплеска в начале каждой секунды.
1257
- *
1258
- * @internal
1259
- */
1260
- declare class RequestQueue {
1261
- #private;
1262
- constructor(options: ResolvedRateLimitOptions, clock?: ItdClock);
1263
- /** Сколько задач выполняется прямо сейчас. */
1264
- get active(): number;
1265
- /** Сколько задач ждёт очереди. */
1266
- get pending(): number;
1267
- /**
1268
- * Ставит задачу в очередь.
1269
- *
1270
- * @returns результат задачи; ошибка задачи пробрасывается без изменений
1650
+ * окончательном `dispose()` клиента и может быть асинхронной. Сам `install()` синхронный:
1651
+ * регистрация расширений завершается до того, как `use()` вернёт управление.
1271
1652
  */
1272
- schedule<T>(task: () => Promise<T>, signal?: AbortSignal): Promise<T>;
1273
- /**
1274
- * Останавливает очередь: снимает отложенную паузу и отклоняет ещё не начатые задачи
1275
- * ошибкой `ItdAbortError`. Уже выполняющиеся задачи доводятся до конца.
1276
- */
1277
- stop(): void;
1278
- /**
1279
- * Придерживает всю очередь на заданное время.
1280
- *
1281
- * Вызывается при получении `429` с заголовком `Retry-After`: тормозить нужно все запросы,
1282
- * а не только тот, который наткнулся на лимит, — иначе остальные продолжат добивать API.
1283
- */
1284
- pause(ms: number): void;
1285
- }
1286
- /**
1287
- * Очереди по хостам: основная и по одной на каждый сервис платформы.
1288
- *
1289
- * @internal
1290
- */
1291
- declare class RequestQueuePool {
1292
- #private;
1293
- constructor(options: ResolvedRateLimitOptions, clock?: ItdClock);
1294
- /** Очередь хоста. */
1295
- for(service: string | undefined): RequestQueue;
1296
- /** Останавливает все очереди. */
1297
- stop(): void;
1653
+ install(api: PluginApi): void | PluginTeardown;
1298
1654
  }
1299
1655
  //#endregion
1300
1656
  //#region src/models/users.d.ts
@@ -1577,21 +1933,22 @@ interface NotificationEvent {
1577
1933
  * ```
1578
1934
  */
1579
1935
  declare function normalizeNotification(input: unknown): Notification;
1936
+ //#endregion
1937
+ //#region src/realtime/transport.d.ts
1938
+ /** Запрос транспорта к конвейеру клиента. */
1939
+ interface RealtimeRequestInput {
1940
+ operationId: BuiltInOperationId;
1941
+ path: string;
1942
+ query?: QueryParams | undefined;
1943
+ signal: AbortSignal;
1944
+ }
1580
1945
  /**
1581
- * Разбирает событие `notification` из потока.
1582
- *
1583
- * Кроме самого уведомления событие несёт служебные поля уровня конверта: актуальный
1584
- * счётчик непрочитанных и признак звука.
1585
- */
1586
- declare function readNotificationEvent(data: unknown): NotificationEvent;
1587
- /**
1588
- * Разбирает событие `unread_count` из потока.
1946
+ * Порт к конвейеру клиента: очередь, авторизация, повторы, плагины и хуки.
1589
1947
  *
1590
- * Возвращает `undefined`, если сервер прислал событие без вложенного `payload`.
1948
+ * Ответ приходит уже разобранным и без обёртки `{ data: }`, а неудача типизированной
1949
+ * ошибкой библиотеки.
1591
1950
  */
1592
- declare function readUnreadCountEvent(data: unknown): number | undefined;
1593
- //#endregion
1594
- //#region src/realtime/transport.d.ts
1951
+ type RealtimeRequest = (input: RealtimeRequestInput) => Promise<unknown>;
1595
1952
  /** Событие, пришедшее по каналу реального времени. */
1596
1953
  interface TransportEvent {
1597
1954
  /** Имя события: `notification`, `unread_count` и другие. */
@@ -1603,8 +1960,16 @@ interface TransportEvent {
1603
1960
  interface TransportContext {
1604
1961
  /** Базовый URL API. */
1605
1962
  baseUrl: string;
1963
+ /** Разрешено ли передавать токен этому сервису. */
1964
+ authorize: boolean;
1606
1965
  /** Реализация `fetch`. */
1607
1966
  fetch: typeof fetch;
1967
+ /**
1968
+ * Выполнение обычных HTTP-запросов транспорта через конвейер клиента.
1969
+ *
1970
+ * Есть только у потока, созданного клиентом: конвейер принадлежит ему.
1971
+ */
1972
+ request?: RealtimeRequest | undefined;
1608
1973
  /**
1609
1974
  * Общие заголовки клиента: `User-Agent`, `X-Device-Id`, заголовки конфигурации
1610
1975
  * и cookie для указанного адреса.
@@ -1621,15 +1986,7 @@ interface TransportContext {
1621
1986
  /** Вызывается, когда соединение установлено. */
1622
1987
  onOpen: () => void;
1623
1988
  }
1624
- /**
1625
- * Канал получения событий в реальном времени.
1626
- *
1627
- * Сейчас у платформы один такой канал — поток `text/event-stream`. Абстракция нужна
1628
- * на будущее: политика безопасности сайта уже разрешает `wss://*.xn--d1ah4a.com`,
1629
- * и когда появится WebSocket, достаточно будет добавить ещё одну реализацию этого
1630
- * интерфейса. Переподключение, обновление токена и разбор уведомлений от транспорта
1631
- * не зависят.
1632
- */
1989
+ /** Канал получения исходных событий в реальном времени. */
1633
1990
  interface RealtimeTransport {
1634
1991
  /** Понятное имя для логов и диагностики. */
1635
1992
  readonly name: string;
@@ -1691,17 +2048,28 @@ type RealtimeUpdateType = RealtimeUpdate['type'];
1691
2048
  type RealtimeUpdateOfType<T extends RealtimeUpdateType> = Extract<RealtimeUpdate, {
1692
2049
  type: T;
1693
2050
  }>;
1694
- /** Контекст обработки одного обновления потока. */
1695
- interface RealtimeContext<U extends RealtimeUpdate = RealtimeUpdate> {
2051
+ /**
2052
+ * Общая форма контекста обработки: то, что есть у любого потока независимо от домена.
2053
+ *
2054
+ * Контекст — обычный объектный литерал, а не класс с геттерами и не `Object.freeze`:
2055
+ * плагины-флейворы присваивают в него свои поля (`ctx.session = …`), а `@itd-api/hydrate`
2056
+ * подменяет `update` и `stream` через `Object.defineProperty`.
2057
+ *
2058
+ * @typeParam U нормализованное обновление домена
2059
+ * @typeParam S поток, который его получил
2060
+ */
2061
+ interface RealtimeContextBase<U = unknown, S = unknown> {
1696
2062
  /** Нормализованные данные обновления. */
1697
2063
  readonly update: U;
1698
2064
  /** Поток, который получил обновление. */
1699
- readonly stream: ItdRealtime;
2065
+ readonly stream: S;
1700
2066
  /** Исходный кадр транспорта. Для начальной REST-синхронизации равен `undefined`. */
1701
2067
  readonly raw: TransportEvent | undefined;
1702
2068
  /** Откуда получены данные. */
1703
2069
  readonly origin: RealtimeUpdateOrigin;
1704
2070
  }
2071
+ /** Контекст обработки одного обновления потока уведомлений. */
2072
+ type RealtimeContext<U extends RealtimeUpdate = RealtimeUpdate> = RealtimeContextBase<U, ItdRealtime>;
1705
2073
  /** Контекст уведомления с типом, суженным фильтром. */
1706
2074
  type RealtimeNotificationContext<T extends NotificationType = NotificationType> = RealtimeContext<RealtimeNotificationUpdate<T>>;
1707
2075
  /** Условия отбора уведомлений. Все указанные поля объединяются через логическое И. */
@@ -1724,32 +2092,23 @@ type RealtimeNotificationSelector<T extends NotificationType = NotificationType>
1724
2092
  /** Продолжает цепочку промежуточных обработчиков потока. */
1725
2093
  type RealtimeNext = () => Promise<void>;
1726
2094
  /** Обрабатывает обновление потока до его передачи подписчикам. */
1727
- type RealtimeMiddleware<C extends RealtimeContext = RealtimeContext> = (context: C, next: RealtimeNext) => void | Promise<void>;
2095
+ type RealtimeMiddleware<C extends RealtimeContextBase = RealtimeContext> = (context: C, next: RealtimeNext) => void | Promise<void>;
2096
+ /** Объект, предоставляющий снимок промежуточного обработчика потока. */
2097
+ interface RealtimeMiddlewareObj<C extends RealtimeContextBase = RealtimeContext> {
2098
+ middleware(): RealtimeMiddleware<C>;
2099
+ }
1728
2100
  /** Асинхронный обработчик нормализованного обновления потока. */
1729
- type RealtimeHandler<C extends RealtimeContext = RealtimeContext> = (context: C) => unknown | Promise<unknown>;
2101
+ type RealtimeHandler<C extends RealtimeContextBase = RealtimeContext> = (context: C) => unknown | Promise<unknown>;
1730
2102
  /** Условие отбора контекста потока. */
1731
- type RealtimePredicate = (context: RealtimeContext) => boolean;
2103
+ type RealtimePredicate<C extends RealtimeContextBase = RealtimeContext> = (context: C) => boolean;
1732
2104
  /** Проверка, сужающая тип контекста потока. */
1733
- type RealtimeTypeGuard<C extends RealtimeContext> = (context: RealtimeContext) => context is C;
2105
+ type RealtimeTypeGuard<C extends B, B extends RealtimeContextBase = RealtimeContext> = (context: B) => context is C;
1734
2106
  /** Ключи, по которым обновления нельзя обрабатывать одновременно. */
1735
- type RealtimeSequentializer = (context: RealtimeContext) => PropertyKey | readonly PropertyKey[] | undefined;
2107
+ type RealtimeSequentializer<C extends RealtimeContextBase = RealtimeContext> = (context: C) => PropertyKey | readonly PropertyKey[] | undefined;
2108
+ /** Выполняет промежуточные обработчики по порядку и запрещает повторный вызов `next()`. */
2109
+ declare function runRealtimeMiddleware<C extends RealtimeContextBase>(middleware: readonly RealtimeMiddleware<C>[], context: C, terminal: RealtimeNext): Promise<void>;
1736
2110
  //#endregion
1737
2111
  //#region src/realtime/reconnect.d.ts
1738
- /**
1739
- * Паузы перед попытками переподключения, мс.
1740
- *
1741
- * Значения совпадают с теми, что использует сайт итд.com, — поведение библиотеки
1742
- * не отличается от привычного пользователю.
1743
- */
1744
- declare const RECONNECT_BACKOFF: readonly number[];
1745
- /** Доля случайного разброса паузы. */
1746
- declare const RECONNECT_JITTER = 0.3;
1747
- /**
1748
- * Сколько раз пытаться переподключиться подряд.
1749
- *
1750
- * После исчерпания поток сообщает `giveup` и ждёт ручного `connect()`.
1751
- */
1752
- declare const MAX_RECONNECT_ATTEMPTS = 15;
1753
2112
  /** Настройки переподключения. */
1754
2113
  interface ReconnectOptions {
1755
2114
  /** Таблица пауз. Последнее значение действует для всех дальнейших попыток. */
@@ -1760,27 +2119,14 @@ interface ReconnectOptions {
1760
2119
  maxAttempts?: number;
1761
2120
  }
1762
2121
  //#endregion
1763
- //#region src/realtime/stream.d.ts
1764
- /** События потока уведомлений. */
1765
- interface RealtimeEvents {
1766
- /** Пришло новое уведомление. */
1767
- notification: NotificationEvent;
1768
- /**
1769
- * Сервер подтвердил подключение и назвал получателя событий.
1770
- *
1771
- * Приходит первым кадром сразу после установки соединения.
1772
- */
1773
- ready: {
1774
- userId: string | undefined;
1775
- };
1776
- /**
1777
- * Получено актуальное число непрочитанных.
1778
- *
1779
- * При подключении клиент может запросить начальное значение через REST. Затем событие
1780
- * возникает, только если счётчик пришёл в потоке. В остальных случаях обновляйте его
1781
- * в приложении либо запрашивайте `itd.notifications.count()`.
1782
- */
1783
- unreadCount: number;
2122
+ //#region src/realtime/engine.d.ts
2123
+ /**
2124
+ * События, которые движок рассылает сам.
2125
+ *
2126
+ * Ни одно из них не зависит от домена, поэтому они одинаковы у любого потока.
2127
+ * Домен расширяет эту карту своими событиями.
2128
+ */
2129
+ interface RealtimeEngineEvents<C extends RealtimeContextBase = RealtimeContextBase> {
1784
2130
  /** Изменилось состояние соединения. */
1785
2131
  status: RealtimeStatus;
1786
2132
  /** Соединение оборвалось; будет предпринята попытка переподключения. */
@@ -1800,19 +2146,47 @@ interface RealtimeEvents {
1800
2146
  };
1801
2147
  /** Попытки исчерпаны — соединение восстановится только ручным `connect()`. */
1802
2148
  giveup: undefined;
1803
- /** Любой исходный кадр транспорта. Отправляется до нормализации и промежуточных обработчиков. */
2149
+ /** Любой исходный кадр транспорта. Отправляется до нормализации и обработчиков. */
1804
2150
  message: TransportEvent;
1805
2151
  /** Промежуточный обработчик потока завершился исключением. */
1806
2152
  middlewareError: {
1807
2153
  error: unknown;
1808
- context: RealtimeContext;
2154
+ context: C;
1809
2155
  };
1810
- /** Обработчик `onUpdate` завершился исключением. */
2156
+ /** Обработчик обновления завершился исключением. */
1811
2157
  handlerError: {
1812
2158
  error: unknown;
1813
- context: RealtimeContext;
2159
+ context: C;
1814
2160
  };
1815
2161
  }
2162
+ //#endregion
2163
+ //#region src/realtime/stream.d.ts
2164
+ /**
2165
+ * События потока уведомлений.
2166
+ *
2167
+ * Общая часть — {@link RealtimeEngineEvents}: статусы, ошибки и переподключение одинаковы
2168
+ * у любого потока. Ниже — то, что есть только у уведомлений.
2169
+ */
2170
+ interface RealtimeEvents<C extends RealtimeContext = RealtimeContext> extends RealtimeEngineEvents<C> {
2171
+ /** Пришло новое уведомление. */
2172
+ notification: NotificationEvent;
2173
+ /**
2174
+ * Сервер подтвердил подключение и назвал получателя событий.
2175
+ *
2176
+ * Приходит первым кадром сразу после установки соединения.
2177
+ */
2178
+ ready: {
2179
+ userId: string | undefined;
2180
+ };
2181
+ /**
2182
+ * Получено актуальное число непрочитанных.
2183
+ *
2184
+ * При подключении клиент может запросить начальное значение через REST. Затем событие
2185
+ * возникает, только если счётчик пришёл в потоке. В остальных случаях обновляйте его
2186
+ * в приложении либо запрашивайте `itd.notifications.count()`.
2187
+ */
2188
+ unreadCount: number;
2189
+ }
1816
2190
  /** Способ получения событий. */
1817
2191
  declare const RealtimeTransportKind: Readonly<{
1818
2192
  /** Поток событий, если среда умеет читать тело по частям, иначе опрос. */
@@ -1824,7 +2198,7 @@ declare const RealtimeTransportKind: Readonly<{
1824
2198
  }>;
1825
2199
  type RealtimeTransportKind = (typeof RealtimeTransportKind)[keyof typeof RealtimeTransportKind];
1826
2200
  /** Настройки потока уведомлений. */
1827
- interface RealtimeOptions extends ReconnectOptions {
2201
+ interface RealtimeOptions<C extends RealtimeContext = RealtimeContext> extends ReconnectOptions {
1828
2202
  /**
1829
2203
  * Транспорт. По умолчанию `auto`: поток событий, если среда умеет читать тело ответа
1830
2204
  * по частям, иначе опрос.
@@ -1867,12 +2241,16 @@ interface RealtimeOptions extends ReconnectOptions {
1867
2241
  /** Максимальное число одновременно обрабатываемых обновлений. По умолчанию 1. */
1868
2242
  concurrency?: number;
1869
2243
  /** Возвращает ключи обновлений, которые нельзя обрабатывать одновременно. */
1870
- sequentialize?: RealtimeSequentializer;
2244
+ sequentialize?: RealtimeSequentializer<C>;
1871
2245
  }
1872
2246
  /** Что поток получает от клиента. */
1873
2247
  interface RealtimeDeps {
1874
2248
  baseUrl: string;
2249
+ /** Разрешено ли транспорту передавать токен этому сервису. */
2250
+ authorize?: boolean | undefined;
1875
2251
  fetch: typeof fetch;
2252
+ /** Конвейер клиента — см. {@link TransportContext.request}. */
2253
+ request?: RealtimeRequest | undefined;
1876
2254
  clock?: ItdClock;
1877
2255
  /** Общие заголовки клиента для адреса — см. {@link TransportContext.baseHeaders}. */
1878
2256
  baseHeaders: (url: string) => Promise<Headers>;
@@ -1897,6 +2275,9 @@ interface RealtimeDeps {
1897
2275
  * Получается вызовом `itd.realtime()`. Соединение поднимается методом {@link connect}
1898
2276
  * и держится само: обрывы, обновление токена и повторные попытки библиотека берёт на себя.
1899
2277
  *
2278
+ * Параметр типа задаёт форму контекста: плагин может расширить её своими полями
2279
+ * (`ItdRealtime<RealtimeContext & SessionFlavor<S>>`) и типизировать обработчики.
2280
+ *
1900
2281
  * @example
1901
2282
  * ```ts
1902
2283
  * import { NotificationType } from 'itd-api';
@@ -1914,12 +2295,12 @@ interface RealtimeDeps {
1914
2295
  * await stream.drain();
1915
2296
  * ```
1916
2297
  */
1917
- declare class ItdRealtime {
2298
+ declare class ItdRealtime<C extends RealtimeContext = RealtimeContext> {
1918
2299
  #private;
1919
- constructor(deps: RealtimeDeps, options?: RealtimeOptions);
2300
+ constructor(deps: RealtimeDeps, options?: RealtimeOptions<C>);
1920
2301
  /** Текущее состояние соединения. */
1921
2302
  get status(): RealtimeStatus;
1922
- /** Какой транспорт используется: `sse` или `poll`. */
2303
+ /** Имя используемого транспорта. */
1923
2304
  get transport(): string;
1924
2305
  /** Базовый URL клиента, создавшего поток. @internal */
1925
2306
  get baseUrl(): string;
@@ -1928,32 +2309,32 @@ declare class ItdRealtime {
1928
2309
  /** Непрозрачная область авторизации создавшего поток клиента. @internal */
1929
2310
  getAuthScope(): string | undefined;
1930
2311
  /** Подписывается на событие потока. @returns функция отписки */
1931
- on<K extends keyof RealtimeEvents>(event: K, listener: Listener<RealtimeEvents[K]>): Unsubscribe;
2312
+ on<K extends keyof RealtimeEvents<C>>(event: K, listener: Listener<RealtimeEvents<C>[K]>): Unsubscribe;
1932
2313
  /** Подписывается на одно срабатывание. */
1933
- once<K extends keyof RealtimeEvents>(event: K, listener: Listener<RealtimeEvents[K]>): Unsubscribe;
2314
+ once<K extends keyof RealtimeEvents<C>>(event: K, listener: Listener<RealtimeEvents<C>[K]>): Unsubscribe;
1934
2315
  /**
1935
- * Добавляет промежуточный обработчик нормализованных обновлений.
2316
+ * Добавляет промежуточный обработчик или объект, предоставляющий его через `middleware()`.
1936
2317
  *
1937
2318
  * Обработчики выполняются в порядке регистрации. Если `next()` не вызван, обновление не
1938
2319
  * передаётся дальше по цепочке, асинхронным обработчикам и слушателям событий.
1939
2320
  *
1940
2321
  * @returns функция удаления обработчика
1941
2322
  */
1942
- use(middleware: RealtimeMiddleware): Unsubscribe;
2323
+ use(middleware: RealtimeMiddleware<C> | RealtimeMiddlewareObj<C>): Unsubscribe;
1943
2324
  /** Подписывает асинхронный обработчик на все нормализованные обновления. */
1944
- onUpdate(handler: RealtimeHandler): Unsubscribe;
2325
+ onUpdate(handler: RealtimeHandler<C>): Unsubscribe;
1945
2326
  /** Подписывает асинхронный обработчик на обновление указанного типа. */
1946
- onUpdate<T extends RealtimeUpdateType>(type: T, handler: RealtimeHandler<RealtimeContext<RealtimeUpdateOfType<T>>>): Unsubscribe;
2327
+ onUpdate<T extends RealtimeUpdateType>(type: T, handler: RealtimeHandler<C & RealtimeContext<RealtimeUpdateOfType<T>>>): Unsubscribe;
1947
2328
  /** Подписывает асинхронный обработчик по функции сужения типа. */
1948
- onUpdate<C extends RealtimeContext>(guard: RealtimeTypeGuard<C>, handler: RealtimeHandler<C>): Unsubscribe;
2329
+ onUpdate<N extends C>(guard: RealtimeTypeGuard<N, C>, handler: RealtimeHandler<N>): Unsubscribe;
1949
2330
  /** Подписывает асинхронный обработчик по пользовательскому условию. */
1950
- onUpdate(predicate: RealtimePredicate, handler: RealtimeHandler): Unsubscribe;
2331
+ onUpdate(predicate: RealtimePredicate<C>, handler: RealtimeHandler<C>): Unsubscribe;
1951
2332
  /** Подписывает асинхронный обработчик на уведомления, подходящие под фильтр. */
1952
- onNotification<T extends NotificationType>(selector: RealtimeNotificationSelector<T>, handler: RealtimeHandler<RealtimeNotificationContext<T>>): Unsubscribe;
2333
+ onNotification<T extends NotificationType>(selector: RealtimeNotificationSelector<T>, handler: RealtimeHandler<C & RealtimeNotificationContext<T>>): Unsubscribe;
1953
2334
  /** Подписывает асинхронный обработчик по функции сужения типа уведомления. */
1954
- onNotification<C extends RealtimeNotificationContext>(guard: (context: RealtimeNotificationContext) => context is C, handler: RealtimeHandler<C>): Unsubscribe;
2335
+ onNotification<N extends C & RealtimeNotificationContext>(guard: (context: C & RealtimeNotificationContext) => context is N, handler: RealtimeHandler<N>): Unsubscribe;
1955
2336
  /** Подписывает асинхронный обработчик по пользовательскому условию. */
1956
- onNotification(predicate: (context: RealtimeNotificationContext) => boolean, handler: RealtimeHandler<RealtimeNotificationContext>): Unsubscribe;
2337
+ onNotification(predicate: (context: C & RealtimeNotificationContext) => boolean, handler: RealtimeHandler<C & RealtimeNotificationContext>): Unsubscribe;
1957
2338
  /**
1958
2339
  * Поднимает соединение.
1959
2340
  *
@@ -1961,6 +2342,8 @@ declare class ItdRealtime {
1961
2342
  * подключения при перерисовке интерфейса.
1962
2343
  *
1963
2344
  * Возвращает управление сразу после запуска: соединение живёт в фоне.
2345
+ *
2346
+ * @throws если создавший поток клиент уже освобождён
1964
2347
  */
1965
2348
  connect(): Promise<void>;
1966
2349
  /** Закрывает соединение и отменяет запланированные попытки. */
@@ -1971,81 +2354,18 @@ declare class ItdRealtime {
1971
2354
  removeAllListeners(): void;
1972
2355
  }
1973
2356
  //#endregion
1974
- //#region src/core/plugins/registry.d.ts
1975
- /**
1976
- * Список подключённых плагинов и собранная из них цепочка обёрток.
1977
- *
1978
- * Живёт в клиенте, а работает в транспорте: {@link HttpClient} прогоняет через `run`
1979
- * каждый запрос, если плагины есть.
1980
- */
1981
- declare class PluginRegistry {
1982
- #private;
1983
- /** Сколько плагинов подключено. */
1984
- get size(): number;
1985
- /** Имена опций активных плагинов. */
1986
- get optionKeys(): ReadonlySet<string>;
1987
- /** Имена плагинов в фактическом порядке выполнения. */
1988
- names(): string[];
1989
- /** Подключён ли плагин с таким именем. */
1990
- has(name: string): boolean;
1991
- /** Проверяет добавление без вызова `install()`. @internal */
1992
- assertCanAdd(plugin: ItdPlugin): void;
1993
- /** Проверяет удаление без изменения реестра. @internal */
1994
- assertCanRemove(name: string): void;
1995
- /**
1996
- * Подключает плагин.
1997
- *
1998
- * @throws {ItdConfigError} если плагин задан неверно, уже подключён, нарушает зависимости
1999
- * или заявил занятое имя опции
2000
- */
2001
- add(plugin: ItdPlugin, context: Omit<PluginContext, 'use' | 'useHooks'>): void;
2002
- /**
2003
- * Отключает плагин и вызывает его функцию очистки.
2004
- *
2005
- * Новые запросы перестают видеть плагин сразу. Если его обёртка уже выполняется,
2006
- * очистка дождётся завершения этого логического запроса.
2007
- *
2008
- * @returns `false`, если такого плагина не было
2009
- */
2010
- remove(name: string): Promise<boolean>;
2011
- /**
2012
- * Отключает все плагины окончательно.
2013
- *
2014
- * Очистка идёт изнутри наружу — в порядке, обратном выполнению обёрток.
2015
- */
2016
- dispose(): Promise<void>;
2017
- /**
2018
- * Объединяет конструкторские хуки с хуками подключаемых плагинов.
2019
- *
2020
- * Возвращённый объект динамический: подключение и отключение плагина начинает действовать
2021
- * со следующего логического запроса без пересоздания транспорта.
2022
- */
2023
- hooks(base: ClientHooks): ClientHooks;
2024
- /**
2025
- * Прогоняет запрос через цепочку обёрток.
2026
- *
2027
- * Снимок цепочки берётся в начале: `unuse()` влияет на новые запросы, но не обрывает
2028
- * уже выполняющийся посередине.
2029
- *
2030
- * @param execute настоящий запрос, вызывается самой внутренней обёрткой
2031
- */
2032
- run(request: RawRequestOptions, execute: (request: RawRequestOptions) => Promise<unknown>): Promise<unknown>;
2033
- }
2034
- //#endregion
2035
2357
  //#region src/core/http.d.ts
2036
2358
  /** Что нужно фасаду для работы. */
2037
2359
  interface HttpClientDeps {
2038
2360
  /** Готовый обработчик — вся цепочка слоёв поверх транспорта. */
2039
2361
  handler: RequestHandler;
2040
- /** Реестр плагинов: у него ресурсы спрашивают имена заявленных опций. */
2041
- plugins: PluginRegistry;
2042
2362
  baseUrl: string;
2043
2363
  }
2044
2364
  /**
2045
2365
  * Точка входа ресурсов в конвейер запросов.
2046
2366
  *
2047
2367
  * Принимает готовый обработчик — цепочку слоёв поверх транспорта, собранную
2048
- * в {@link ItdClient}, — и отдаёт ресурсам метод `request` и имена опций плагинов.
2368
+ * во внутреннем runtime клиента, — и отдаёт ресурсам методы `request`/`operation`.
2049
2369
  * О слоях и их порядке ресурсы не знают.
2050
2370
  */
2051
2371
  declare class HttpClient {
@@ -2053,13 +2373,6 @@ declare class HttpClient {
2053
2373
  constructor(deps: HttpClientDeps);
2054
2374
  /** Базовый URL, к которому обращается клиент. */
2055
2375
  get baseUrl(): string;
2056
- /**
2057
- * Имена опций запроса, заявленные плагинами.
2058
- *
2059
- * Читается ресурсами: они переносят в транспорт только известные поля, а чужие,
2060
- * если их никто не заявил, отсеивают.
2061
- */
2062
- get pluginOptionKeys(): ReadonlySet<string>;
2063
2376
  /**
2064
2377
  * Выполняет запрос к API через собранный конвейер.
2065
2378
  *
@@ -2069,7 +2382,11 @@ declare class HttpClient {
2069
2382
  * @throws {ItdAbortError} если запрос отменён через `signal`
2070
2383
  * @throws {ItdNetworkError} если запрос не дошёл до сервера
2071
2384
  */
2072
- request<T = unknown>(options: PipelineRequest): Promise<T>;
2385
+ request<T = unknown>(options: PipelineRequestInput): Promise<T>;
2386
+ /** Выполняет встроенную семантическую операцию, подставляя её HTTP-метод из каталога. */
2387
+ operation<T = unknown>(operationId: BuiltInOperationId, options: Omit<PipelineRequest, 'operationId' | 'method'>): Promise<T>;
2388
+ /** Выполняет внутреннюю операцию финализации после начала `ItdClient.dispose()`. @internal */
2389
+ cleanupOperation<T = unknown>(operationId: BuiltInOperationId, options: Omit<PipelineRequest, 'operationId' | 'method'>): Promise<T>;
2073
2390
  }
2074
2391
  //#endregion
2075
2392
  //#region src/models/account.d.ts
@@ -2240,11 +2557,6 @@ declare class Paginator<T> implements AsyncIterable<T> {
2240
2557
  }
2241
2558
  //#endregion
2242
2559
  //#region src/resources/base.d.ts
2243
- /** Параметры перебираемого списка: опции запроса плюс предел числа страниц. */
2244
- interface ListParams extends RequestOptions {
2245
- /** Ограничение числа страниц при переборе. */
2246
- maxPages?: number | undefined;
2247
- }
2248
2560
  /**
2249
2561
  * Описание перебираемого эндпоинта.
2250
2562
  *
@@ -2254,7 +2566,9 @@ interface ListParams extends RequestOptions {
2254
2566
  * @typeParam T тип элемента списка
2255
2567
  * @typeParam P тип параметров метода
2256
2568
  */
2257
- interface ListingSpec<T, P extends ListParams> {
2569
+ interface ListingSpec<T, P extends object> {
2570
+ /** Стабильная семантическая операция списка. */
2571
+ operationId: BuiltInOperationId | ((params: P) => BuiltInOperationId);
2258
2572
  /** Путь эндпоинта. */
2259
2573
  path: (params: P) => string;
2260
2574
  /** Параметры запроса без полей пагинации — их добавит перебор. */
@@ -2267,35 +2581,25 @@ interface ListingSpec<T, P extends ListParams> {
2267
2581
  start: (params: P) => PageState;
2268
2582
  }
2269
2583
  /** Пара методов, собранная из {@link ListingSpec}: разовая загрузка и перебор. */
2270
- interface Listing<T, P extends ListParams> {
2584
+ interface Listing<T, P extends object> {
2271
2585
  /** Загружает одну страницу с позиции, заданной параметрами. */
2272
- list(params: P): Promise<Page<T>>;
2586
+ list(params: P, options?: RequestOptions): Promise<Page<T>>;
2273
2587
  /** Перебирает страницы, сама подставляя позиции. */
2274
- iterate(params: P): Paginator<T>;
2588
+ iterate(params: P, options?: PaginationOptions): Paginator<T>;
2275
2589
  }
2276
2590
  /** Общая основа всех групп методов клиента. */
2277
2591
  declare class BaseResource {
2278
2592
  /** @internal */
2279
2593
  protected readonly http: HttpClient;
2280
2594
  constructor(http: HttpClient);
2281
- /**
2282
- * Переносит опции запроса в описание транспорта.
2283
- *
2284
- * Копируются только поля {@link REQUEST_OPTION_KEYS} и опции, заявленные плагинами:
2285
- * параметры методов наследуют {@link RequestOptions} и приносят с собой `limit`, `cursor`
2286
- * и прочее, чему в описании запроса делать нечего. Чужие опции плагинов библиотека
2287
- * не понимает, но обязана донести до обёрток нетронутыми.
2288
- */
2289
- protected requestOptions(options: RequestOptions | undefined): Partial<RequestOptions>;
2290
2595
  /**
2291
2596
  * Собирает перебор страниц.
2292
2597
  *
2293
2598
  * @param mode схема пагинации эндпоинта
2294
2599
  * @param load загружает одну страницу для указанной позиции
2295
- * @param options `maxPages` и `signal`, а также `start` позиция, с которой продолжить
2600
+ * @param options только управление самим перебором: предел, отмена и начальная позиция
2296
2601
  */
2297
- protected paginate<T>(mode: PaginationMode, load: (state: PageState) => Promise<Page<T>>, options?: RequestOptions & {
2298
- maxPages?: number;
2602
+ protected paginate<T>(mode: PaginationMode, load: (state: PageState) => Promise<Page<T>>, options?: PaginationOptions & {
2299
2603
  start?: PageState;
2300
2604
  }): Paginator<T>;
2301
2605
  /**
@@ -2307,6 +2611,7 @@ declare class BaseResource {
2307
2611
  * @example
2308
2612
  * ```ts
2309
2613
  * #feed = this.paginated<Post, FeedParams>({
2614
+ * operationId: 'posts.list',
2310
2615
  * path: () => '/api/posts',
2311
2616
  * query: (p) => ({ tab: p.tab, limit: p.limit }),
2312
2617
  * start: (p) => (p.cursor ? { cursor: p.cursor } : {}),
@@ -2315,7 +2620,7 @@ declare class BaseResource {
2315
2620
  * });
2316
2621
  * ```
2317
2622
  */
2318
- protected paginated<T, P extends ListParams>(spec: ListingSpec<T, P>): Listing<T, P>;
2623
+ protected paginated<T, P extends object>(spec: ListingSpec<T, P>): Listing<T, P>;
2319
2624
  }
2320
2625
  //#endregion
2321
2626
  //#region src/resources/auth.d.ts
@@ -2858,10 +3163,9 @@ interface PinPostResult {
2858
3163
  //#endregion
2859
3164
  //#region src/resources/comments.d.ts
2860
3165
  /** Параметры запроса ответов на комментарий. */
2861
- interface RepliesParams extends RequestOptions {
3166
+ interface RepliesParams {
2862
3167
  limit?: number;
2863
3168
  page?: number;
2864
- maxPages?: number;
2865
3169
  }
2866
3170
  /**
2867
3171
  * Комментарии и ответы на них.
@@ -2879,9 +3183,9 @@ declare class CommentsResource extends BaseResource {
2879
3183
  *
2880
3184
  * Здесь пагинация **постраничная**, в отличие от комментариев к посту, где курсорная.
2881
3185
  */
2882
- replies(commentId: string, params?: RepliesParams): Promise<Page<Comment>>;
3186
+ replies(commentId: string, params?: RepliesParams, options?: RequestOptions): Promise<Page<Comment>>;
2883
3187
  /** Перебирает ответы на комментарий. */
2884
- iterateReplies(commentId: string, params?: RepliesParams): Paginator<Comment>;
3188
+ iterateReplies(commentId: string, params?: RepliesParams, options?: PaginationOptions): Paginator<Comment>;
2885
3189
  /**
2886
3190
  * Отвечает на комментарий.
2887
3191
  *
@@ -2913,7 +3217,7 @@ interface UploadedFile {
2913
3217
  url: string;
2914
3218
  }
2915
3219
  /** Настройки загрузки. */
2916
- interface UploadOptions extends RequestOptions {
3220
+ interface UploadOptions {
2917
3221
  /** Имя файла. Используется для определения MIME, если тип не задан. */
2918
3222
  filename?: string;
2919
3223
  /** MIME-тип. По умолчанию определяется по имени или `Blob`. */
@@ -2925,8 +3229,6 @@ interface UploadOptions extends RequestOptions {
2925
3229
  /** Размер очереди библиотеки при потоковой передаче. */
2926
3230
  streamBufferBytes?: number | undefined;
2927
3231
  }
2928
- /** Таймаут одной попытки загрузки файла — 5 минут. */
2929
- declare const DEFAULT_UPLOAD_TIMEOUT = 300000;
2930
3232
  /** Файлы и медиа. */
2931
3233
  declare class FilesResource extends BaseResource {
2932
3234
  #private;
@@ -2939,9 +3241,9 @@ declare class FilesResource extends BaseResource {
2939
3241
  * Потоковый источник открывается заново при каждой повторной попытке. Буферный источник
2940
3242
  * после успешного чтения переиспользуется.
2941
3243
  */
2942
- upload(input: FileInput, options?: UploadOptions): Promise<UploadedFile>;
3244
+ upload(input: FileInput, uploadOptions?: UploadOptions, requestOptions?: RequestOptions): Promise<UploadedFile>;
2943
3245
  /** Загружает несколько файлов последовательно, сохраняя порядок. */
2944
- uploadMany(files: FileInput[], options?: UploadOptions): Promise<string[]>;
3246
+ uploadMany(files: FileInput[], uploadOptions?: UploadOptions, requestOptions?: RequestOptions): Promise<string[]>;
2945
3247
  /**
2946
3248
  * Загружает сведения о файле.
2947
3249
  *
@@ -2954,10 +3256,9 @@ declare class FilesResource extends BaseResource {
2954
3256
  //#endregion
2955
3257
  //#region src/resources/hashtags.d.ts
2956
3258
  /** Параметры запроса постов по хэштегу. */
2957
- interface HashtagPostsParams extends RequestOptions {
3259
+ interface HashtagPostsParams {
2958
3260
  limit?: number;
2959
3261
  cursor?: string;
2960
- maxPages?: number;
2961
3262
  }
2962
3263
  /**
2963
3264
  * Хэштеги.
@@ -2973,29 +3274,28 @@ declare class HashtagsResource extends BaseResource {
2973
3274
  */
2974
3275
  search(query?: string, params?: {
2975
3276
  limit?: number;
2976
- } & RequestOptions): Promise<Hashtag[]>;
3277
+ }, options?: RequestOptions): Promise<Hashtag[]>;
2977
3278
  /** Загружает трендовые хэштеги. */
2978
3279
  trending(params?: {
2979
3280
  limit?: number;
2980
- } & RequestOptions): Promise<Hashtag[]>;
3281
+ }, options?: RequestOptions): Promise<Hashtag[]>;
2981
3282
  /**
2982
3283
  * Загружает страницу постов по хэштегу.
2983
3284
  *
2984
3285
  * @param tag название без решётки; кодируется автоматически, поэтому кириллица
2985
3286
  * и пробелы допустимы
2986
3287
  */
2987
- posts(tag: string, params?: HashtagPostsParams): Promise<Page<Post>>;
3288
+ posts(tag: string, params?: HashtagPostsParams, options?: RequestOptions): Promise<Page<Post>>;
2988
3289
  /** Перебирает посты по хэштегу. */
2989
- iteratePosts(tag: string, params?: HashtagPostsParams): Paginator<Post>;
3290
+ iteratePosts(tag: string, params?: HashtagPostsParams, options?: PaginationOptions): Paginator<Post>;
2990
3291
  }
2991
3292
  //#endregion
2992
3293
  //#region src/resources/notifications.d.ts
2993
3294
  /** Параметры запроса списка уведомлений. */
2994
- interface NotificationListParams extends RequestOptions {
3295
+ interface NotificationListParams {
2995
3296
  limit?: number;
2996
3297
  /** Смещение от начала списка. */
2997
3298
  offset?: number;
2998
- maxPages?: number;
2999
3299
  }
3000
3300
  /** Изменяемые настройки уведомлений. */
3001
3301
  type UpdateNotificationSettingsInput = Partial<NotificationSettings>;
@@ -3018,7 +3318,7 @@ declare class NotificationsResource extends BaseResource {
3018
3318
  * const next = await itd.notifications.list({ limit: 20, offset: page.nextOffset });
3019
3319
  * ```
3020
3320
  */
3021
- list(params?: NotificationListParams): Promise<Page<Notification>>;
3321
+ list(params?: NotificationListParams, options?: RequestOptions): Promise<Page<Notification>>;
3022
3322
  /**
3023
3323
  * Перебирает уведомления.
3024
3324
  *
@@ -3029,7 +3329,7 @@ declare class NotificationsResource extends BaseResource {
3029
3329
  * }
3030
3330
  * ```
3031
3331
  */
3032
- iterate(params?: NotificationListParams): Paginator<Notification>;
3332
+ iterate(params?: NotificationListParams, options?: PaginationOptions): Paginator<Notification>;
3033
3333
  /** Загружает число непрочитанных уведомлений. */
3034
3334
  count(options?: RequestOptions): Promise<number>;
3035
3335
  /**
@@ -3519,7 +3819,7 @@ type PostUpdateInput = UpdatePostInput | PostBuilder | ((builder: PostBuilder) =
3519
3819
  //#endregion
3520
3820
  //#region src/resources/posts.d.ts
3521
3821
  /** Параметры запроса ленты. */
3522
- interface FeedParams extends RequestOptions {
3822
+ interface FeedParams {
3523
3823
  /** Вкладка ленты. По умолчанию сервер отдаёт популярное. */
3524
3824
  tab?: FeedTab;
3525
3825
  /** Сколько постов на страницу. */
@@ -3530,21 +3830,18 @@ interface FeedParams extends RequestOptions {
3530
3830
  * Передавайте значение как есть: его формат зависит от вкладки и может измениться.
3531
3831
  */
3532
3832
  cursor?: string;
3533
- /** Ограничение числа страниц при переборе. */
3534
- maxPages?: number;
3535
3833
  }
3536
3834
  /** Параметры запроса постов пользователя. */
3537
- interface UserPostsParams extends RequestOptions {
3835
+ interface UserPostsParams {
3538
3836
  limit?: number;
3539
3837
  cursor?: string;
3540
3838
  /** Порядок сортировки. */
3541
3839
  sort?: string;
3542
3840
  /** Закреплённый пост, чтобы сервер поднял его наверх. */
3543
3841
  pinnedPostId?: string;
3544
- maxPages?: number;
3545
3842
  }
3546
3843
  /** Параметры запроса комментариев к посту. */
3547
- interface CommentsParams extends RequestOptions {
3844
+ interface CommentsParams {
3548
3845
  limit?: number;
3549
3846
  /**
3550
3847
  * Курсор следующей страницы: идентификатор последнего полученного комментария.
@@ -3553,7 +3850,6 @@ interface CommentsParams extends RequestOptions {
3553
3850
  */
3554
3851
  cursor?: string;
3555
3852
  sort?: CommentSort;
3556
- maxPages?: number;
3557
3853
  }
3558
3854
  /**
3559
3855
  * Посты: лента, публикация, реакции, репосты, комментарии.
@@ -3574,7 +3870,7 @@ declare class PostsResource extends BaseResource {
3574
3870
  * const next = await itd.posts.list({ tab: FeedTab.Following, cursor: page.nextCursor ?? undefined });
3575
3871
  * ```
3576
3872
  */
3577
- list(params?: FeedParams): Promise<Page<Post>>;
3873
+ list(params?: FeedParams, options?: RequestOptions): Promise<Page<Post>>;
3578
3874
  /**
3579
3875
  * Перебирает ленту, сама подставляя курсоры.
3580
3876
  *
@@ -3585,7 +3881,7 @@ declare class PostsResource extends BaseResource {
3585
3881
  * }
3586
3882
  * ```
3587
3883
  */
3588
- iterate(params?: FeedParams): Paginator<Post>;
3884
+ iterate(params?: FeedParams, options?: PaginationOptions): Paginator<Post>;
3589
3885
  /**
3590
3886
  * Публикует пост.
3591
3887
  *
@@ -3652,22 +3948,22 @@ declare class PostsResource extends BaseResource {
3652
3948
  *
3653
3949
  * Принимает и UUID, и имя пользователя.
3654
3950
  */
3655
- byUser(user: UserRef, params?: UserPostsParams): Promise<Page<Post>>;
3951
+ byUser(user: UserRef, params?: UserPostsParams, options?: RequestOptions): Promise<Page<Post>>;
3656
3952
  /** Перебирает стену пользователя. Что именно в неё входит — см. {@link byUser}. */
3657
- iterateByUser(user: UserRef, params?: UserPostsParams): Paginator<Post>;
3953
+ iterateByUser(user: UserRef, params?: UserPostsParams, options?: PaginationOptions): Paginator<Post>;
3658
3954
  /** Загружает страницу постов, которые пользователь отметил реакцией. */
3659
- likedByUser(user: UserRef, params?: UserPostsParams): Promise<Page<Post>>;
3955
+ likedByUser(user: UserRef, params?: UserPostsParams, options?: RequestOptions): Promise<Page<Post>>;
3660
3956
  /** Перебирает посты, которые пользователь отметил реакцией. */
3661
- iterateLikedByUser(user: UserRef, params?: UserPostsParams): Paginator<Post>;
3957
+ iterateLikedByUser(user: UserRef, params?: UserPostsParams, options?: PaginationOptions): Paginator<Post>;
3662
3958
  /**
3663
3959
  * Загружает страницу комментариев к посту.
3664
3960
  *
3665
3961
  * У этого эндпоинта курсор и признак продолжения лежат рядом со списком, а не внутри
3666
3962
  * объекта `pagination`, как у остальных, — разница скрыта внутри.
3667
3963
  */
3668
- comments(postId: string, params?: CommentsParams): Promise<Page<Comment>>;
3964
+ comments(postId: string, params?: CommentsParams, options?: RequestOptions): Promise<Page<Comment>>;
3669
3965
  /** Перебирает комментарии к посту. */
3670
- iterateComments(postId: string, params?: CommentsParams): Paginator<Comment>;
3966
+ iterateComments(postId: string, params?: CommentsParams, options?: PaginationOptions): Paginator<Comment>;
3671
3967
  /**
3672
3968
  * Комментирует пост.
3673
3969
  *
@@ -3812,8 +4108,8 @@ declare class SubscriptionResource extends BaseResource {
3812
4108
  }
3813
4109
  //#endregion
3814
4110
  //#region src/resources/telemetry.d.ts
3815
- /** Общие опции запроса телеметрии. */
3816
- interface TelemetryOptions extends RequestOptions {
4111
+ /** Параметры событий телеметрии. */
4112
+ interface TelemetryOptions {
3817
4113
  /** Переопределяет идентификатор сессии телеметрии (`sid`) для этого запроса. */
3818
4114
  sid?: string;
3819
4115
  }
@@ -3945,7 +4241,7 @@ interface TelemetryBatch {
3945
4241
  *
3946
4242
  * Опции позволяют заменить, например, отменённый `signal` при повторной попытке.
3947
4243
  */
3948
- flush(options?: TelemetryOptions): Promise<void>;
4244
+ flush(options?: RequestOptions): Promise<void>;
3949
4245
  /** Отправляет накопленные события и закрывает накопитель. */
3950
4246
  close(): Promise<void>;
3951
4247
  }
@@ -3957,24 +4253,25 @@ interface TelemetryBatch {
3957
4253
  */
3958
4254
  declare class TelemetryResource extends BaseResource {
3959
4255
  #private;
4256
+ constructor(http: HttpClient);
3960
4257
  /** Идентификатор сессии телеметрии, общий для всех событий этого ресурса. */
3961
4258
  get sessionId(): string;
3962
4259
  /** Отправляет события просмотра постов (`POST /api/v1/i`). */
3963
- dwell(entries: readonly DwellEntry[], options?: TelemetryOptions): Promise<unknown>;
4260
+ dwell(entries: readonly DwellEntry[], telemetryOptions?: TelemetryOptions, requestOptions?: RequestOptions): Promise<unknown>;
3964
4261
  /** Отправляет события взаимодействия с контентом (`POST /api/v1/x`). */
3965
- interaction(entries: readonly InteractionEntry[], options?: TelemetryOptions): Promise<unknown>;
4262
+ interaction(entries: readonly InteractionEntry[], telemetryOptions?: TelemetryOptions, requestOptions?: RequestOptions): Promise<unknown>;
3966
4263
  /** Начинает измерять время просмотра и отправляет результат после `finish()`. */
3967
- startView(input: ViewTrackerInput, options?: ViewTrackerOptions): ViewTracker;
4264
+ startView(input: ViewTrackerInput, options?: ViewTrackerOptions, requestOptions?: RequestOptions): ViewTracker;
3968
4265
  /** Отправляет событие открытия фотографии. */
3969
- photoOpen(input: PhotoOpenInput, options?: TelemetryOptions): Promise<unknown>;
4266
+ photoOpen(input: PhotoOpenInput, telemetryOptions?: TelemetryOptions, requestOptions?: RequestOptions): Promise<unknown>;
3970
4267
  /** Отправляет событие прогресса просмотра видео. */
3971
- videoProgress(input: VideoProgressInput, options?: TelemetryOptions): Promise<unknown>;
4268
+ videoProgress(input: VideoProgressInput, telemetryOptions?: TelemetryOptions, requestOptions?: RequestOptions): Promise<unknown>;
3972
4269
  /**
3973
4270
  * Создаёт накопитель с явными `flush()` и `close()`.
3974
4271
  *
3975
4272
  * Создание и добавление записей не выполняют сетевых запросов.
3976
4273
  */
3977
- batch(options?: TelemetryBatchOptions): TelemetryBatch;
4274
+ batch(options?: TelemetryBatchOptions, requestOptions?: RequestOptions): TelemetryBatch;
3978
4275
  /** Закрывает все созданные накопители, отправляя оставшиеся записи. */
3979
4276
  close(): Promise<void>;
3980
4277
  }
@@ -3986,12 +4283,11 @@ declare class TelemetryResource extends BaseResource {
3986
4283
  * ⚠️ Списки подписчиков, подписок и заблокированных на сервере **не листаются**:
3987
4284
  * `page` он игнорирует, а `limit` зажимает на 20. Подробности — в {@link UsersResource.followers}.
3988
4285
  */
3989
- interface UserListParams extends RequestOptions {
4286
+ interface UserListParams {
3990
4287
  /** Сколько записей вернуть. Значения больше 20 сервер молча уменьшает до 20. */
3991
4288
  limit?: number;
3992
4289
  /** Номер страницы. Сервер его игнорирует — оставлен на случай, если пагинацию починят. */
3993
4290
  page?: number;
3994
- maxPages?: number;
3995
4291
  }
3996
4292
  /** Изменяемые поля своего профиля. */
3997
4293
  interface UpdateProfileInput {
@@ -4013,7 +4309,7 @@ type UpdatePrivacyInput = Partial<PrivacySettings>;
4013
4309
  declare class UsersResource extends BaseResource {
4014
4310
  #private;
4015
4311
  constructor(http: HttpClient, deps: {
4016
- uploadFile: (file: FileInput, options?: UploadOptions) => Promise<UploadedFile>;
4312
+ uploadFile: (file: FileInput, uploadOptions?: UploadOptions, requestOptions?: RequestOptions) => Promise<UploadedFile>;
4017
4313
  });
4018
4314
  /** Загружает свой профиль — с подпиской и признаком подтверждённого телефона. */
4019
4315
  me(options?: RequestOptions): Promise<MyProfile>;
@@ -4030,7 +4326,7 @@ declare class UsersResource extends BaseResource {
4030
4326
  * await itd.users.setBanner(file, { filename: 'banner.webp' });
4031
4327
  * ```
4032
4328
  */
4033
- setBanner(file: FileInput, options?: UploadOptions): Promise<MyProfile>;
4329
+ setBanner(file: FileInput, uploadOptions?: UploadOptions, requestOptions?: RequestOptions): Promise<MyProfile>;
4034
4330
  /** Удаляет баннер профиля, устанавливая `bannerId` в `null`. */
4035
4331
  removeBanner(options?: RequestOptions): Promise<MyProfile>;
4036
4332
  /** Деактивирует аккаунт. Вернуть его можно через {@link restore}. */
@@ -4060,7 +4356,7 @@ declare class UsersResource extends BaseResource {
4060
4356
  /** Ищет пользователей по строке запроса. */
4061
4357
  search(query: string, params?: {
4062
4358
  limit?: number;
4063
- } & RequestOptions): Promise<UserSummary[]>;
4359
+ }, options?: RequestOptions): Promise<UserSummary[]>;
4064
4360
  /** Загружает рекомендации, на кого подписаться. */
4065
4361
  whoToFollow(options?: RequestOptions): Promise<UserSummary[]>;
4066
4362
  /** Загружает рейтинг кланов. */
@@ -4084,18 +4380,18 @@ declare class UsersResource extends BaseResource {
4084
4380
  * Числу `total` доверять тоже не стоит: оно расходится с `followersCount` из профиля —
4085
4381
  * на проверенных аккаунтах занижено примерно на 1–4%.
4086
4382
  */
4087
- followers(user: UserRef, params?: UserListParams): Promise<Page<UserSummary>>;
4383
+ followers(user: UserRef, params?: UserListParams, options?: RequestOptions): Promise<Page<UserSummary>>;
4088
4384
  /**
4089
4385
  * Перебирает подписчиков.
4090
4386
  *
4091
4387
  * ⚠️ Перебор закончится после первых 20 записей: сервер список не листает —
4092
4388
  * см. {@link followers}. Метод оставлен на случай, если пагинацию починят.
4093
4389
  */
4094
- iterateFollowers(user: UserRef, params?: UserListParams): Paginator<UserSummary>;
4390
+ iterateFollowers(user: UserRef, params?: UserListParams, options?: PaginationOptions): Paginator<UserSummary>;
4095
4391
  /** Загружает подписки пользователя. Ограничения те же, что у {@link followers}. */
4096
- following(user: UserRef, params?: UserListParams): Promise<Page<UserSummary>>;
4392
+ following(user: UserRef, params?: UserListParams, options?: RequestOptions): Promise<Page<UserSummary>>;
4097
4393
  /** Перебирает подписки. Закончится после первых 20 записей — см. {@link followers}. */
4098
- iterateFollowing(user: UserRef, params?: UserListParams): Paginator<UserSummary>;
4394
+ iterateFollowing(user: UserRef, params?: UserListParams, options?: PaginationOptions): Paginator<UserSummary>;
4099
4395
  /**
4100
4396
  * Проверяет, подписаны ли вы, сразу для нескольких пользователей.
4101
4397
  *
@@ -4113,9 +4409,9 @@ declare class UsersResource extends BaseResource {
4113
4409
  /** Снимает блокировку. */
4114
4410
  unblock(user: UserRef, options?: RequestOptions): Promise<void>;
4115
4411
  /** Загружает заблокированных пользователей. Ограничения те же, что у {@link followers}. */
4116
- blocked(params?: UserListParams): Promise<Page<UserSummary>>;
4412
+ blocked(params?: UserListParams, options?: RequestOptions): Promise<Page<UserSummary>>;
4117
4413
  /** Перебирает заблокированных. Закончится после первых 20 записей — см. {@link followers}. */
4118
- iterateBlocked(params?: UserListParams): Paginator<UserSummary>;
4414
+ iterateBlocked(params?: UserListParams, options?: PaginationOptions): Paginator<UserSummary>;
4119
4415
  /** Загружает настройки приватности. */
4120
4416
  getPrivacy(options?: RequestOptions): Promise<PrivacySettings>;
4121
4417
  /** Обновляет настройки приватности. Передавайте только изменяемые поля. */
@@ -4151,19 +4447,6 @@ declare global {
4151
4447
  readonly asyncDispose: unique symbol;
4152
4448
  }
4153
4449
  }
4154
- /**
4155
- * Скрытые параметры конструктора — не часть публичного API.
4156
- *
4157
- * @internal
4158
- */
4159
- interface ItdClientInternals {
4160
- /**
4161
- * Готовая очередь запросов — так {@link ItdAccounts} с `rateLimitScope: 'shared'` даёт
4162
- * нескольким клиентам одну на всех. Свою клиент в этом случае не заводит и, что важнее,
4163
- * не гасит при `close()`: чужие ожидающие запросы это отменило бы.
4164
- */
4165
- queues?: RequestQueuePool | undefined;
4166
- }
4167
4450
  /**
4168
4451
  * Клиент API итд.com.
4169
4452
  *
@@ -4198,32 +4481,32 @@ interface ItdClientInternals {
4198
4481
  declare class ItdClient {
4199
4482
  #private;
4200
4483
  /** Авторизация, сессии и пароли. */
4201
- readonly auth: AuthResource;
4484
+ get auth(): AuthResource;
4202
4485
  /** Профили, подписки, блокировки, приватность. */
4203
- readonly users: UsersResource;
4486
+ get users(): UsersResource;
4204
4487
  /** Лента, публикация, реакции, репосты, комментарии к постам. */
4205
- readonly posts: PostsResource;
4488
+ get posts(): PostsResource;
4206
4489
  /** Ответы на комментарии и действия над ними. */
4207
- readonly comments: CommentsResource;
4490
+ get comments(): CommentsResource;
4208
4491
  /** Загрузка файлов и медиа. */
4209
- readonly files: FilesResource;
4492
+ get files(): FilesResource;
4210
4493
  /** Уведомления: список, счётчик, отметки о прочтении, настройки. */
4211
- readonly notifications: NotificationsResource;
4494
+ get notifications(): NotificationsResource;
4212
4495
  /** Хэштеги и посты по ним. */
4213
- readonly hashtags: HashtagsResource;
4496
+ get hashtags(): HashtagsResource;
4214
4497
  /** Глобальный поиск по пользователям и хэштегам. */
4215
- readonly search: SearchResource;
4498
+ get search(): SearchResource;
4216
4499
  /** Жалобы на контент и пользователей. */
4217
- readonly reports: ReportsResource;
4500
+ get reports(): ReportsResource;
4218
4501
  /** Верификация профиля. */
4219
- readonly verification: VerificationResource;
4502
+ get verification(): VerificationResource;
4220
4503
  /** Подписка и способы оплаты. */
4221
- readonly subscription: SubscriptionResource;
4504
+ get subscription(): SubscriptionResource;
4222
4505
  /** Сведения о платформе: версии приложений, изменения, анонсы, баннер события. */
4223
- readonly platform: PlatformResource;
4506
+ get platform(): PlatformResource;
4224
4507
  /** Телеметрия просмотров. */
4225
- readonly telemetry: TelemetryResource;
4226
- constructor(options?: ItdClientOptions, internals?: ItdClientInternals);
4508
+ get telemetry(): TelemetryResource;
4509
+ constructor(options?: ItdClientOptions);
4227
4510
  /** Базовый URL, к которому обращается клиент. */
4228
4511
  get baseUrl(): string;
4229
4512
  /**
@@ -4236,26 +4519,33 @@ declare class ItdClient {
4236
4519
  * ```ts
4237
4520
  * const raw = await itd.request({ method: 'GET', path: '/api/posts', raw: true });
4238
4521
  * ```
4522
+ *
4523
+ * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}
4239
4524
  */
4240
4525
  request<T = unknown>(options: RawRequestOptions): Promise<T>;
4241
4526
  /**
4242
4527
  * Подключает плагин.
4243
4528
  *
4244
- * Плагин работает на уровне транспорта: видит запрос до отправки и разобранный ответ,
4245
- * поэтому одна обёртка охватывает сразу все методы клиента. Подключать можно в любой
4246
- * момент, но обычно это делают сразу после создания клиента.
4529
+ * Плагин может независимо регистрировать transformer логической операции и interceptor
4530
+ * транспортной попытки. Оба контракта охватывают все методы клиента. Подключать плагин
4531
+ * можно в любой момент, но обычно это делают сразу после создания клиента.
4247
4532
  *
4248
4533
  * @throws {ItdConfigError} если плагин задан неверно или уже подключён
4534
+ * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}
4249
4535
  *
4250
4536
  * @example
4251
4537
  * ```ts
4252
4538
  * import { crypt } from '@itd-api/crypto';
4253
4539
  *
4254
4540
  * itd.use(crypt());
4255
- * await itd.posts.create({ content: 'секрет' }, { encrypt: 'invis' });
4541
+ * await itd.posts.create({
4542
+ * content: 'секрет',
4543
+ * }, {
4544
+ * extensions: { crypto: { encrypt: 'invisible' } },
4545
+ * });
4256
4546
  * ```
4257
4547
  */
4258
- use(plugin: ItdPlugin): this;
4548
+ use(plugin: ClientPlugin): this;
4259
4549
  /** Имена подключённых плагинов в фактическом порядке выполнения обёрток. */
4260
4550
  pluginNames(): string[];
4261
4551
  /** Подключён ли плагин с таким именем. */
@@ -4281,6 +4571,7 @@ declare class ItdClient {
4281
4571
  * поддоменам. Стороннему хосту токен нужно разрешить явно: `auth: true`.
4282
4572
  *
4283
4573
  * @throws {ItdConfigError} если определение неверно или имя уже занято
4574
+ * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}
4284
4575
  *
4285
4576
  * @example Сервис платформы на поддомене — токен уходит сам
4286
4577
  * ```ts
@@ -4335,18 +4626,37 @@ declare class ItdClient {
4335
4626
  *
4336
4627
  * await stream.connect();
4337
4628
  * ```
4629
+ *
4630
+ * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}
4338
4631
  */
4339
4632
  realtime(options?: RealtimeOptions): ItdRealtime;
4340
4633
  /**
4341
4634
  * Освобождает ресурсы клиента: закрывает все потоки уведомлений, отправляет открытые
4342
4635
  * накопители {@link telemetry}, затем останавливает очередь запросов.
4343
4636
  *
4344
- * Метод дожидается активных обработчиков потока. После вызова клиентом можно пользоваться
4345
- * снова; ранее созданный поток можно запустить повторным `connect()`.
4637
+ * Метод дожидается активных обработчиков потока, но не дольше `shutdownTimeout`. После
4638
+ * вызова клиентом можно пользоваться снова; ранее созданный поток можно запустить
4639
+ * повторным `connect()`.
4346
4640
  *
4347
4641
  * Общая очередь, полученная от {@link ItdAccounts}, не останавливается: её гасит сам
4348
4642
  * контейнер, когда закрывает все аккаунты разом.
4349
4643
  *
4644
+ * Терминальное освобождение — это {@link dispose}.
4645
+ *
4646
+ * @throws {ItdStateError} если обработчики потока не завершились за отведённый срок
4647
+ */
4648
+ close(): Promise<void>;
4649
+ /**
4650
+ * Окончательно освобождает клиент: выполняет {@link close}, отменяет незавершённые
4651
+ * запросы и отключает все плагины.
4652
+ *
4653
+ * Терминальное состояние устанавливается сразу при первом вызове. После этого новые
4654
+ * запросы, подключение плагинов, регистрация сервисов и создание или повторный запуск
4655
+ * realtime-потоков завершаются с {@link ItdStateError}. Повторные вызовы возвращают
4656
+ * тот же результат очистки.
4657
+ *
4658
+ * Ожидание обработчиков потока и операций плагинов ограничено `shutdownTimeout`.
4659
+ *
4350
4660
  * @example
4351
4661
  * ```ts
4352
4662
  * await using itd = new ItdClient({ auth: token });
@@ -4354,14 +4664,6 @@ declare class ItdClient {
4354
4664
  * // dispose() вызовется сам на выходе из блока
4355
4665
  * ```
4356
4666
  */
4357
- close(): Promise<void>;
4358
- /**
4359
- * Окончательно освобождает клиент: выполняет {@link close} и отключает все плагины.
4360
- *
4361
- * В отличие от `close()`, после `dispose()` плагины не восстанавливаются автоматически.
4362
- * Сам клиент остаётся пригоден для обычных запросов; при необходимости плагины можно
4363
- * подключить заново через {@link use}.
4364
- */
4365
4667
  dispose(): Promise<void>;
4366
4668
  /** Позволяет использовать клиент с `await using`. */
4367
4669
  [Symbol.asyncDispose](): Promise<void>;
@@ -4386,7 +4688,11 @@ declare class ItdClient {
4386
4688
  * ```
4387
4689
  */
4388
4690
  getUserId(): Promise<UserId | undefined>;
4389
- /** Восстанавливает сохранённую сессию, включая cookie. */
4691
+ /**
4692
+ * Восстанавливает сохранённую сессию, включая cookie.
4693
+ *
4694
+ * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}
4695
+ */
4390
4696
  setSession(session: ItdSession): Promise<void>;
4391
4697
  }
4392
4698
  /**
@@ -4418,7 +4724,7 @@ interface ItdAccountsOptions extends Omit<ItdClientOptions, 'auth' | 'storage' |
4418
4724
  /** Общее хранилище сессий всех аккаунтов. По умолчанию {@link MemoryMultiTokenStorage}. */
4419
4725
  storage?: MultiTokenStorage | undefined;
4420
4726
  /** Плагины, подключаемые каждому аккаунту, в том числе добавленному позже. */
4421
- plugins?: readonly ItdPlugin[] | undefined;
4727
+ plugins?: readonly ClientPlugin[] | undefined;
4422
4728
  /**
4423
4729
  * Как делить очередь запросов. По умолчанию `'account'` — своя у каждого.
4424
4730
  *
@@ -4584,7 +4890,7 @@ declare class ItdAccounts {
4584
4890
  * accounts.use(crypt());
4585
4891
  * ```
4586
4892
  */
4587
- use(plugin: ItdPlugin): this;
4893
+ use(plugin: ClientPlugin): this;
4588
4894
  /** Имена общих плагинов в фактическом порядке выполнения обёрток. */
4589
4895
  pluginNames(): string[];
4590
4896
  /** Подключён ли общий плагин с таким именем. */
@@ -4637,7 +4943,9 @@ declare class ItdAccounts {
4637
4943
  * Окончательно освобождает контейнер и отключает общие плагины у всех аккаунтов.
4638
4944
  *
4639
4945
  * Для временной остановки потоков и очереди без отключения плагинов используйте
4640
- * {@link close}.
4946
+ * {@link close}. Терминальное состояние устанавливается сразу: контейнер отзывает
4947
+ * storage-срезы и подписки, а новые аккаунты, запросы его клиентов и плагины после
4948
+ * первого `dispose()` больше не допускаются.
4641
4949
  */
4642
4950
  dispose(): Promise<void>;
4643
4951
  /** Позволяет использовать контейнер с `await using`. */
@@ -4683,6 +4991,8 @@ declare const ItdErrorKind: Readonly<{
4683
4991
  readonly Timeout: "timeout";
4684
4992
  /** Запрос отменён через `AbortSignal`. */
4685
4993
  readonly Abort: "abort";
4994
+ /** Операция невозможна в текущем состоянии объекта. */
4995
+ readonly State: "state";
4686
4996
  /** Не удалось получить или подготовить содержимое вложения. */
4687
4997
  readonly File: "file";
4688
4998
  /** Некорректная конфигурация или аргументы — обнаружено до обращения к сети. */
@@ -4952,6 +5262,17 @@ declare class ItdAbortError extends ItdError {
4952
5262
  cause?: unknown;
4953
5263
  });
4954
5264
  }
5265
+ /**
5266
+ * Операция невозможна в текущем состоянии объекта.
5267
+ *
5268
+ * Например, клиент уже окончательно освобождён через `dispose()` и не может выполнять
5269
+ * новые запросы или создавать realtime-потоки.
5270
+ */
5271
+ declare class ItdStateError extends ItdError {
5272
+ constructor(message: string, options?: {
5273
+ cause?: unknown;
5274
+ });
5275
+ }
4955
5276
  /**
4956
5277
  * Некорректная конфигурация или аргументы — обнаружено до обращения к сети.
4957
5278
  *
@@ -4959,7 +5280,9 @@ declare class ItdAbortError extends ItdError {
4959
5280
  * с одним вариантом ответа.
4960
5281
  */
4961
5282
  declare class ItdConfigError extends ItdError {
4962
- constructor(message: string);
5283
+ constructor(message: string, options?: {
5284
+ cause?: unknown;
5285
+ });
4963
5286
  }
4964
5287
  /** Любая ошибка, порождённая этой библиотекой. */
4965
5288
  declare function isItdError(value: unknown): value is ItdError;
@@ -4967,6 +5290,8 @@ declare function isItdError(value: unknown): value is ItdError;
4967
5290
  declare function isItdApiError(value: unknown): value is ItdApiError;
4968
5291
  /** Ошибка получения или чтения вложения. */
4969
5292
  declare function isItdFileError(value: unknown): value is ItdFileError;
5293
+ /** Операция невозможна в текущем состоянии объекта. */
5294
+ declare function isItdStateError(value: unknown): value is ItdStateError;
4970
5295
  /** Ошибка валидации: `VALIDATION_ERROR` либо статус `400`/`422`. */
4971
5296
  declare function isItdValidationError(value: unknown): value is ItdValidationError;
4972
5297
  /** Ошибка авторизации: истёкший или отозванный токен. */
@@ -5068,17 +5393,6 @@ declare function statusDays(service: ServiceStatus): (StatusDay | null)[];
5068
5393
  declare function formatNotificationText(notification: Notification): string;
5069
5394
  //#endregion
5070
5395
  //#region src/notifications/type-map.d.ts
5071
- /**
5072
- * Соответствие коротких имён типов уведомлений развёрнутым.
5073
- *
5074
- * Сервер — и в списке, и в потоке событий — присылает короткие имена: `like`, `comment`,
5075
- * `reply`, `repost`, `comment_like`. Развёрнутые (`post_reaction`, `post_comment`)
5076
- * встречаются в оформлении интерфейса, поэтому библиотека приводит типы к ним:
5077
- * они однозначно называют и объект, и действие.
5078
- *
5079
- * Пришедшее значение всегда остаётся в поле `rawType`.
5080
- */
5081
- declare const NOTIFICATION_TYPE_ALIASES: Readonly<Record<string, NotificationType>>;
5082
5396
  /**
5083
5397
  * Приводит имя типа к каноническому.
5084
5398
  *
@@ -5116,20 +5430,9 @@ declare function isKnownNotificationType(type: string): boolean;
5116
5430
  */
5117
5431
  declare function resolveNotificationUrl(notification: Notification): string;
5118
5432
  //#endregion
5119
- //#region src/realtime/poll.d.ts
5120
- /** Настройки опроса. */
5121
- interface PollTransportOptions {
5122
- /** Часы опроса. Обычно подменяются только в тестах. */
5123
- clock?: ItdClock;
5124
- /** Как часто опрашивать сервер, мс. По умолчанию 15 000. */
5125
- interval?: number;
5126
- /** Сколько уведомлений запрашивать за раз. По умолчанию 20. */
5127
- limit?: number;
5128
- }
5129
- //#endregion
5130
5433
  //#region src/realtime/router.d.ts
5131
5434
  /** Выбирает маршрут обновления. `undefined` и `null` означают отсутствие маршрута. */
5132
- type RealtimeRouteSelector<K extends PropertyKey, C extends RealtimeContext = RealtimeContext> = (context: C) => K | null | undefined | Promise<K | null | undefined>;
5435
+ type RealtimeRouteSelector<K extends PropertyKey, C extends RealtimeContextBase = RealtimeContext> = (context: C) => K | null | undefined | Promise<K | null | undefined>;
5133
5436
  /**
5134
5437
  * Направляет обновления потока в именованные цепочки промежуточных обработчиков.
5135
5438
  *
@@ -5144,43 +5447,122 @@ type RealtimeRouteSelector<K extends PropertyKey, C extends RealtimeContext = Re
5144
5447
  * }
5145
5448
  * await next();
5146
5449
  * });
5147
- * stream.use(router.middleware());
5450
+ * stream.use(router);
5148
5451
  * ```
5149
5452
  */
5150
- declare class RealtimeRouter<K extends PropertyKey = PropertyKey, C extends RealtimeContext = RealtimeContext> {
5453
+ declare class RealtimeRouter<K extends PropertyKey = PropertyKey, C extends RealtimeContextBase = RealtimeContext> implements RealtimeMiddlewareObj<C> {
5151
5454
  #private;
5152
5455
  constructor(selector: RealtimeRouteSelector<K, C>);
5153
5456
  /** Добавляет промежуточные обработчики к маршруту и возвращает функцию их удаления. */
5154
5457
  route(key: K, ...middleware: readonly RealtimeMiddleware<C>[]): Unsubscribe;
5155
5458
  /** Добавляет промежуточные обработчики для обновлений без зарегистрированного маршрута. */
5156
5459
  otherwise(...middleware: readonly RealtimeMiddleware<C>[]): Unsubscribe;
5157
- /** Возвращает промежуточный обработчик для `stream.use()`. */
5460
+ /** Возвращает снимок маршрутов для `stream.use(router)` или ручной композиции. */
5158
5461
  middleware(): RealtimeMiddleware<C>;
5159
5462
  }
5160
5463
  //#endregion
5161
- //#region src/realtime/sse.d.ts
5162
- /** Путь потока уведомлений. */
5163
- declare const STREAM_PATH = "/api/notifications/stream";
5164
- /** Настройки SSE-транспорта. */
5165
- interface SseTransportOptions {
5166
- /** Часы потока. Обычно подменяются только в тестах. */
5167
- clock?: ItdClock;
5464
+ //#region src/realtime/composer.d.ts
5465
+ /** Функция или объектный middleware, который можно добавить в {@link RealtimeComposer}. */
5466
+ type RealtimeMiddlewareLike<C extends RealtimeContextBase = RealtimeContext> = RealtimeMiddleware<C> | RealtimeMiddlewareObj<C>;
5467
+ /** Один middleware или последовательность middleware для ветки composer. */
5468
+ type RealtimeMiddlewareGroup<C extends RealtimeContextBase = RealtimeContext> = RealtimeMiddlewareLike<C> | readonly RealtimeMiddlewareLike<C>[];
5469
+ /** Синхронное или асинхронное условие ветвления composer. */
5470
+ type RealtimeFilter<C extends RealtimeContextBase = RealtimeContext> = (context: C) => boolean | Promise<boolean>;
5471
+ /** Ошибка локальной realtime-ветки вместе с контекстом обрабатываемого обновления. */
5472
+ interface RealtimeErrorContext<C extends RealtimeContextBase = RealtimeContext> {
5473
+ /** Исходное исключение middleware. */
5474
+ readonly error: unknown;
5475
+ /** Контекст обновления, на котором завершилась ветка. */
5476
+ readonly context: C;
5477
+ }
5478
+ /** Обработчик локальной границы ошибок composer. */
5479
+ type RealtimeErrorBoundary<C extends RealtimeContextBase = RealtimeContext> = (failure: RealtimeErrorContext<C>, next: RealtimeNext) => unknown | Promise<unknown>;
5480
+ /** Именованные ветки для {@link RealtimeComposer.route}. */
5481
+ type RealtimeRouteTable<K extends string | symbol, C extends RealtimeContextBase = RealtimeContext> = Partial<Record<K, RealtimeMiddlewareGroup<C>>>;
5482
+ /**
5483
+ * Собирает переиспользуемый feature-модуль из realtime middleware.
5484
+ *
5485
+ * Composer не открывает соединение и не планирует конкурентность: готовый объект подключается
5486
+ * через `stream.use(composer)`, а выполнение остаётся обязанностью существующего dispatcher.
5487
+ * Для каждого принятого update используется снимок всей вложенной структуры composer.
5488
+ *
5489
+ * @example
5490
+ * ```ts
5491
+ * const feature = new RealtimeComposer<AppRealtimeContext>();
5492
+ * const safe = feature.errorBoundary(reportFeatureError);
5493
+ * safe.filter(isPostUpdate).use(handlePost);
5494
+ * stream.use(feature);
5495
+ * ```
5496
+ */
5497
+ declare class RealtimeComposer<C extends RealtimeContextBase = RealtimeContext> implements RealtimeMiddlewareObj<C> {
5498
+ #private;
5499
+ constructor(...middleware: readonly RealtimeMiddlewareLike<C>[]);
5500
+ /** Добавляет middleware в конец текущей onion-цепочки. */
5501
+ use(...middleware: readonly RealtimeMiddlewareLike<C>[]): this;
5502
+ /** Создаёт дочернюю ветку, выполняемую только когда type guard принимает контекст. */
5503
+ filter<N extends C>(predicate: RealtimeTypeGuard<N, C>, ...middleware: readonly RealtimeMiddlewareLike<N>[]): RealtimeComposer<N>;
5504
+ /** Создаёт дочернюю ветку по синхронному или асинхронному условию. */
5505
+ filter(predicate: RealtimeFilter<C>, ...middleware: readonly RealtimeMiddlewareLike<C>[]): RealtimeComposer<C>;
5168
5506
  /**
5169
- * Сколько миллисекунд ждать данных, прежде чем считать соединение мёртвым.
5507
+ * Направляет контекст в одну именованную ветку.
5170
5508
  *
5171
- * Сервер не присылает keep-alive, а оборванное TCP-соединение может не закрыться
5172
- * само без этой проверки поток «тихо умирает» и новых уведомлений не приходит.
5173
- * По умолчанию 90 000. `0` отключает проверку.
5509
+ * Неизвестный ключ без fallback пропускает update следующему внешнему middleware. Для
5510
+ * динамической регистрации и числовых ключей используйте {@link RealtimeRouter} напрямую.
5174
5511
  */
5175
- idleTimeout?: number;
5512
+ route<K extends string | symbol>(selector: RealtimeRouteSelector<K, C>, routes: RealtimeRouteTable<K, C>, fallback?: RealtimeMiddlewareGroup<C>): this;
5176
5513
  /**
5177
- * Сколько миллисекунд ждать ответа на запрос потока, прежде чем оборвать попытку.
5514
+ * Создаёт дочернюю ветку с локальной границей ошибок.
5178
5515
  *
5179
- * Проверка молчания ({@link idleTimeout}) начинается только после получения тела ответа.
5180
- * Если `fetch` завис на установке соединения, без этого таймаута переподключение не
5181
- * запустится до системного сетевого таймаута. По умолчанию 20 000. `0` отключает проверку.
5516
+ * Граница защищает только переданные и затем добавленные в возвращённый composer middleware.
5517
+ * Ошибки внешней цепочки намеренно не перехватываются. Обработчик может вызвать `next()`,
5518
+ * чтобы после ошибки продолжить внешнюю цепочку, либо повторно выбросить исключение. Внешняя
5519
+ * цепочка начинается после полного завершения защищённой ветки, а не входит в её onion-вызов.
5182
5520
  */
5183
- handshakeTimeout?: number;
5521
+ errorBoundary(handler: RealtimeErrorBoundary<C>, ...middleware: readonly RealtimeMiddlewareLike<C>[]): RealtimeComposer<C>;
5522
+ /** Возвращает snapshot-aware middleware для `stream.use()` или вложенного composer. */
5523
+ middleware(): RealtimeMiddleware<C>;
5524
+ }
5525
+ //#endregion
5526
+ //#region src/realtime/websocket.d.ts
5527
+ /** Дополнительные параметры конструктора, поддерживаемые Node-реализациями вроде `ws`. */
5528
+ interface WebSocketImplementationOptions {
5529
+ headers?: Record<string, string> | undefined;
5530
+ handshakeTimeout?: number | undefined;
5531
+ }
5532
+ /** Конструктор WebSocket, который можно передать вместо глобальной реализации. */
5533
+ interface WebSocketLike {
5534
+ new (url: string | URL, protocols?: string | string[], options?: WebSocketImplementationOptions): unknown;
5535
+ }
5536
+ /** Определяет, был ли отказ до открытия сокета вызван недействительным токеном. */
5537
+ type WebSocketOpenFailureClassifier = (error: unknown, signal: AbortSignal) => boolean | Promise<boolean>;
5538
+ /** Настройки WebSocket-транспорта. */
5539
+ interface WebSocketTransportOptions {
5540
+ /** Путь апгрейда. По умолчанию `/api/ws`. */
5541
+ path?: string | undefined;
5542
+ /** Реализация WebSocket для сред без глобальной либо для передачи заголовков апгрейда. */
5543
+ webSocketImpl?: WebSocketLike | undefined;
5544
+ /** Способ передачи токена. `auto` выбирает заголовок при инъекции и query иначе. */
5545
+ auth?: 'query' | 'header' | 'auto' | undefined;
5546
+ /** Молчание открытого соединения до переподключения, мс. По умолчанию 90 000. */
5547
+ idleTimeout?: number | undefined;
5548
+ /** Период текстового `ping`, мс. По умолчанию 30 000. */
5549
+ keepAlive?: number | undefined;
5550
+ /** Максимальное время установки соединения, мс. По умолчанию 20 000. */
5551
+ handshakeTimeout?: number | undefined;
5552
+ /**
5553
+ * Проверяет отказ до `open`, когда среда скрыла HTTP-статус WebSocket-upgrade.
5554
+ * `true` преобразует отказ в {@link UnauthorizedStreamError}.
5555
+ */
5556
+ classifyOpenFailure?: WebSocketOpenFailureClassifier | undefined;
5557
+ /** Часы транспорта. Обычно подменяются только в тестах. */
5558
+ clock?: ItdClock | undefined;
5559
+ }
5560
+ /** Транспорт исходных realtime-событий поверх стандартного WebSocket. */
5561
+ declare class WebSocketTransport implements RealtimeTransport {
5562
+ #private;
5563
+ readonly name = "ws";
5564
+ constructor(options?: WebSocketTransportOptions);
5565
+ connect(context: TransportContext): Promise<void>;
5184
5566
  }
5185
5567
  //#endregion
5186
5568
  //#region src/spans/render.d.ts
@@ -5214,5 +5596,5 @@ interface RenderSpansOptions {
5214
5596
  */
5215
5597
  declare function renderSpans(content: string, spans?: readonly Span[] | null | undefined, options?: RenderSpansOptions): string;
5216
5598
  //#endregion
5217
- export { ALLOWED_MIME_TYPES, AUDIO_MIME_TYPES, AUTH_FLAG_COOKIE, AUTH_PATHS, AccessType, type AccountEvents, type Actor, type AddAccountOptions, type AllowedMimeType, type Announcement, type AnnouncementButton, type Attachment, AttachmentType, type AudioMimeType, type AuthEvents, type AuthIdentity, type AuthInput, type AuthResource, type AuthState, type Author, type AutoSpansOptions, BUILT_IN_SERVICES, type BuilderInput, type CaptchaCredentials, type ChangelogEntry, type Clan, type ClientHooks, type Comment, type CommentBuilder, type CommentInput, type CommentReplyTo, CommentSort, type CommentsParams, type CommentsResource, type CreateCommentInput, type CreatePollInput, type CreatePostData, type CreatePostInput, type CreateReportInput, type Credentials, type CredentialsAuth, DEFAULT_BASE_URL, DEFAULT_FILE_STREAM_BUFFER_BYTES, DEFAULT_STATUS_BASE_URL, DEFAULT_TIMEOUT, DEFAULT_UPLOAD_TIMEOUT, DEFAULT_URL_FILE_MAX_BYTES, DEFAULT_USER_AGENT, DEVICE_ID_HEADER, DetectedRuntime, type DwellEntry, type ErrorContextHook, type FeedParams, FeedTab, type FileContent, type FileContext, type FileInput, type FileStreamContent, type FileStreamOptions, FileTransferMode, type FilesResource, type FollowResult, type ForgotPasswordInput, type FromStreamOptions, type Hashtag, type HashtagPostsParams, type HashtagsResource, IMAGE_MIME_TYPES, type ImageMimeType, IncidentKind, type InteractionEntry, InteractionType, type IsoDate, ItdAbortError, ItdAccounts, type ItdAccountsOptions, ItdApiError, type ItdApiErrorInit, ItdApiErrorKind, ItdAuthError, type ItdBuilder, ItdClient, type ItdClientOptions, type ItdClock, ItdConfigError, ItdConflictError, ItdError, ItdErrorCode, ItdErrorKind, type ItdFieldErrors, ItdFileError, ItdFileErrorReason, ItdForbiddenError, ItdNetworkError, ItdNotFoundError, ItdPhoneVerificationError, type ItdPlugin, ItdRateLimitError, ItdRealtime, ItdServerError, type ItdSession, ItdTimeoutError, ItdValidationError, LIBRARY_VERSION, type LazyFile, type LikeResult, LikesVisibility, type Listener, type Logger, type Loose, MAX_RECONNECT_ATTEMPTS, type MarkupBuilder, type MarkupContent, type MarkupInput, type MarkupSpan, MemoryMultiTokenStorage, MemoryTokenStorage, type MultiTokenStorage, type MyProfile, NOTIFICATION_TYPE_ALIASES, type Notification, type NotificationEvent, type NotificationEventOfType, type NotificationListParams, type NotificationOfType, type NotificationSettings, NotificationType, type NotificationsResource, type Page, type PageState, PaginationMode, Paginator, type PaginatorOptions, type ParseMarkupOptions, type PaymentMethod, type PhotoOpenInput, type Pin, type PinPostResult, type PinsResult, type PlatformClientVersion, type PlatformResource, type PlatformStatus, type PlatformVersions, type PluginContext, type PluginTeardown, type Poll, type PollBuilder, type PollInput, type PollOption, type PollTransportOptions, type Portal, type Post, type PostBuilder, type PostInput, type PostStats, type PostUpdateInput, type PostsResource, type PrivacySettings, type Profile, type PublicProfile, type QueryParams, type QueryValue, RECONNECT_BACKOFF, RECONNECT_JITTER, REFRESH_COOKIE, REFRESH_COOKIE_PATH, REQUEST_OPTION_KEYS, type RateLimitOptions, type RateLimitScope, type RawRequestOptions, type RealtimeContext, type RealtimeDeps, type RealtimeEvents, type RealtimeHandler, type RealtimeMiddleware, type RealtimeNext, type RealtimeNotificationContext, type RealtimeNotificationFilter, type RealtimeNotificationSelector, type RealtimeNotificationUpdate, type RealtimeOptions, type RealtimePredicate, type RealtimeRouteSelector, RealtimeRouter, type RealtimeSequentializer, RealtimeStatus, type RealtimeTransport, RealtimeTransportKind, type RealtimeTypeGuard, type RealtimeUnknownUpdate, type RealtimeUnreadCountUpdate, type RealtimeUpdate, type RealtimeUpdateOfType, RealtimeUpdateOrigin, RealtimeUpdateType, type ReconnectOptions, type RecordStorageSource, type RemoveAccountOptions, type RenderSpansOptions, type RepliesParams, type Report, type ReportBuilder, type ReportInput, ReportReason, ReportTargetType, type ReportsResource, type RequestContext, type RequestOptions, type ResetPasswordInput, type ResponseContext, type RetryContext, type RetryOptions, RuntimeMode, STATUS_SERVICE, STREAM_PATH, type SearchResource, type SearchResult, type ServiceDefinition, ServiceRegistry, ServiceState, type ServiceStatus, type Session, type SignInResult, SignInStatus, type Span, SpanRenderFormat, SpanType, type SseTransportOptions, type StatusDay, type StatusIncidentLine, type StreamFile, type Subscription, type SubscriptionResource, type SubscriptionState, TURNSTILE_SITE_KEY, type TelemetryBatch, type TelemetryBatchOptions, type TelemetryClock, type TelemetryOptions, type TelemetryResource, type TextMarkup, type TokenStorage, type Transformer, type TransportContext, type TransportEvent, UnauthorizedStreamError, type Unsubscribe, type UpdateNotificationSettingsInput, type UpdatePostInput, type UpdatePrivacyInput, type UpdateProfileInput, type UploadOptions, type UploadedFile, type UrlFile, type UrlFileOptions, type UserId, type UserListParams, type UserPostsParams, type UserRef, type UserSummary, type UsersResource, VIDEO_MIME_TYPES, type VerificationResource, type VerificationStatus, type VideoMimeType, type VideoProgressInput, ViewReason, ViewSource, type ViewTracker, type ViewTrackerInput, type ViewTrackerOptions, WallAccess, autoSpans, canonicalNotificationType, comment, createAccounts, createClient, createMultiTokenStorage, createRecordMultiStorage, createTokenStorage, formatNotificationText, fromStream, fromUrl, isBuilder, isItdApiError, isItdAuthError, isItdConflictError, isItdError, isItdFileError, isItdForbiddenError, isItdNotFoundError, isItdPhoneVerificationError, isItdRateLimitError, isItdServerError, isItdValidationError, isKnownNotificationType, isMyProfile, mapPage, markup, normalizeNotification, parseHtml, parseMarkdown, poll, post, readNotificationEvent, readUnreadCountEvent, renderSpans, report, resolveNotificationUrl, scopedTokenStorage, statusDays, systemClock, toDate, utcStampToIso };
5599
+ export { ALLOWED_MIME_TYPES, AUDIO_MIME_TYPES, AccessType, type AccountEvents, type Actor, type AddAccountOptions, type AllowedMimeType, type Announcement, type AnnouncementButton, type Attachment, AttachmentType, type AttemptContext, type AttemptExtensions, type AttemptInterceptor, type AttemptNext, type AudioMimeType, type AuthEvents, type AuthIdentity, type AuthInput, type AuthResource, type AuthState, type Author, type AutoSpansOptions, type BuilderInput, type BuiltInOperationId, type CaptchaCredentials, type ChangelogEntry, type Clan, type ClientHooks, type ClientPlugin, type Comment, type CommentBuilder, type CommentInput, type CommentReplyTo, CommentSort, type CommentsParams, type CommentsResource, type CreateCommentInput, type CreatePollInput, type CreatePostData, type CreatePostInput, type CreateReportInput, type Credentials, type CredentialsAuth, type CustomOperationId, DEFAULT_BASE_URL, type DwellEntry, type EnumerableKeyValueStore, type ErrorContextHook, type FeedParams, FeedTab, type FileContent, type FileContext, type FileInput, type FileStreamContent, type FileStreamOptions, FileTransferMode, type FilesResource, type FollowResult, type ForgotPasswordInput, type FromStreamOptions, type Hashtag, type HashtagPostsParams, type HashtagsResource, IMAGE_MIME_TYPES, type ImageMimeType, IncidentKind, type InteractionEntry, InteractionType, type IsoDate, ItdAbortError, ItdAccounts, type ItdAccountsOptions, ItdApiError, type ItdApiErrorInit, ItdApiErrorKind, ItdAuthError, type ItdBuilder, ItdClient, type ItdClientOptions, type ItdClock, ItdConfigError, ItdConflictError, ItdError, ItdErrorCode, ItdErrorKind, type ItdFieldErrors, ItdFileError, ItdFileErrorReason, ItdForbiddenError, ItdNetworkError, ItdNotFoundError, ItdPhoneVerificationError, ItdRateLimitError, ItdRealtime, ItdServerError, type ItdSession, ItdStateError, ItdTimeoutError, ItdValidationError, type KeyValueCodec, type KeyValueStore, type KeyValueStoreKeys, type KeyValueStoreResult, LIBRARY_VERSION, type LazyFile, type LikeResult, LikesVisibility, type Listener, type Logger, type Loose, type MarkupBuilder, type MarkupContent, type MarkupInput, type MarkupSpan, MemoryKeyValueStore, MemoryMultiTokenStorage, MemoryTokenStorage, type MultiTokenStorage, type MultiTokenStorageAdapterOptions, type MyProfile, type Notification, type NotificationEvent, type NotificationEventOfType, type NotificationListParams, type NotificationOfType, type NotificationSettings, NotificationType, type NotificationsResource, OPERATIONS, type OperationDefinition, type OperationExtensions, type OperationId, type OperationMethod, type OperationRequestOptions, type OperationTransformer, type Page, type PageState, PaginationMode, type PaginationOptions, Paginator, type PaginatorOptions, type ParseMarkupOptions, type PaymentMethod, type PhotoOpenInput, type Pin, type PinPostResult, type PinsResult, type PlatformClientVersion, type PlatformResource, type PlatformStatus, type PlatformVersions, type PluginApi, type PluginTeardown, type Poll, type PollBuilder, type PollInput, type PollOption, type Portal, type Post, type PostBuilder, type PostInput, type PostStats, type PostUpdateInput, type PostsResource, type PrivacySettings, type Profile, type PublicProfile, type QueryParams, type QueryValue, type RateLimitOptions, type RateLimitScope, type RawRequestOptions, RealtimeComposer, type RealtimeContext, type RealtimeContextBase, type RealtimeEngineEvents, type RealtimeErrorBoundary, type RealtimeErrorContext, type RealtimeEvents, type RealtimeFilter, type RealtimeHandler, type RealtimeMiddleware, type RealtimeMiddlewareGroup, type RealtimeMiddlewareLike, type RealtimeMiddlewareObj, type RealtimeNext, type RealtimeNotificationContext, type RealtimeNotificationFilter, type RealtimeNotificationSelector, type RealtimeNotificationUpdate, type RealtimeOptions, type RealtimePredicate, type RealtimeRequest, type RealtimeRequestInput, type RealtimeRouteSelector, type RealtimeRouteTable, RealtimeRouter, type RealtimeSequentializer, RealtimeStatus, type RealtimeTransport, RealtimeTransportKind, type RealtimeTypeGuard, type RealtimeUnknownUpdate, type RealtimeUnreadCountUpdate, type RealtimeUpdate, type RealtimeUpdateOfType, RealtimeUpdateOrigin, RealtimeUpdateType, type ReconnectOptions, type RecordKeyValueStoreSource, type RemoveAccountOptions, type RenderSpansOptions, type RepliesParams, type Report, type ReportBuilder, type ReportInput, ReportReason, ReportTargetType, type ReportsResource, type RequestContext, type RequestExtensions, type RequestOptions, type ResetPasswordInput, type ResponseContext, type RetryContext, type RetryDecisionContext, type RetryOptions, RetrySafety, RuntimeMode, STATUS_SERVICE, type SearchResource, type SearchResult, type ServiceDefinition, ServiceState, type ServiceStatus, type Session, type SignInResult, SignInStatus, type Span, SpanRenderFormat, SpanType, type StatusDay, type StatusIncidentLine, type StreamFile, type Subscription, type SubscriptionResource, type SubscriptionState, TURNSTILE_SITE_KEY, type TelemetryBatch, type TelemetryBatchOptions, type TelemetryClock, type TelemetryOptions, type TelemetryResource, type TextMarkup, type TokenStorage, type TokenStorageAdapterOptions, type TransportContext, type TransportEvent, UnauthorizedStreamError, type Unsubscribe, type UpdateNotificationSettingsInput, type UpdatePostInput, type UpdatePrivacyInput, type UpdateProfileInput, type UploadOptions, type UploadedFile, type UrlFile, type UrlFileOptions, type UserId, type UserListParams, type UserPostsParams, type UserRef, type UserSummary, type UsersResource, VIDEO_MIME_TYPES, type VerificationResource, type VerificationStatus, type VideoMimeType, type VideoProgressInput, ViewReason, ViewSource, type ViewTracker, type ViewTrackerInput, type ViewTrackerOptions, WallAccess, type WebSocketImplementationOptions, type WebSocketLike, type WebSocketOpenFailureClassifier, WebSocketTransport, type WebSocketTransportOptions, autoSpans, canonicalNotificationType, comment, createAccounts, createClient, createKeyValueStore, createMultiTokenStorage, createRecordKeyValueStore, createTokenStorage, formatNotificationText, fromStream, fromUrl, isBuilder, isBuiltInOperationId, isEnumerableKeyValueStore, isItdApiError, isItdAuthError, isItdConflictError, isItdError, isItdFileError, isItdForbiddenError, isItdNotFoundError, isItdPhoneVerificationError, isItdRateLimitError, isItdServerError, isItdStateError, isItdValidationError, isKnownNotificationType, isMyProfile, mapPage, markup, normalizeNotification, operationMethod, operationRetrySafety, parseHtml, parseMarkdown, poll, post, renderSpans, report, resolveNotificationUrl, runRealtimeMiddleware, scopedTokenStorage, statusDays, systemClock, toDate, utcStampToIso, withCodec, withNamespace };
5218
5600
  //# sourceMappingURL=index.d.ts.map