@knocklabs/client 0.8.6 → 0.8.7

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.
@@ -417,6 +417,36 @@ var Feed = /*#__PURE__*/function () {
417
417
 
418
418
  return markAsUnread;
419
419
  }()
420
+ }, {
421
+ key: "markAsInteracted",
422
+ value: function () {
423
+ var _markAsInteracted = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(itemOrItems) {
424
+ var now;
425
+ return _regenerator["default"].wrap(function _callee7$(_context7) {
426
+ while (1) {
427
+ switch (_context7.prev = _context7.next) {
428
+ case 0:
429
+ now = new Date().toISOString();
430
+ this.optimisticallyPerformStatusUpdate(itemOrItems, "interacted", {
431
+ read_at: now,
432
+ interacted_at: now
433
+ }, "unread_count");
434
+ return _context7.abrupt("return", this.makeStatusUpdate(itemOrItems, "interacted"));
435
+
436
+ case 3:
437
+ case "end":
438
+ return _context7.stop();
439
+ }
440
+ }
441
+ }, _callee7, this);
442
+ }));
443
+
444
+ function markAsInteracted(_x5) {
445
+ return _markAsInteracted.apply(this, arguments);
446
+ }
447
+
448
+ return markAsInteracted;
449
+ }()
420
450
  /*
421
451
  Marking one or more items as archived should:
422
452
  - Decrement the badge count for any unread / unseen items
@@ -427,12 +457,12 @@ var Feed = /*#__PURE__*/function () {
427
457
  }, {
428
458
  key: "markAsArchived",
429
459
  value: function () {
430
- var _markAsArchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(itemOrItems) {
460
+ var _markAsArchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(itemOrItems) {
431
461
  var _this$store3, getState, setState, state, shouldOptimisticallyRemoveItems, normalizedItems, itemIds, unseenCount, unreadCount, updatedMetadata, entriesToSet;
432
462
 
433
- return _regenerator["default"].wrap(function _callee7$(_context7) {
463
+ return _regenerator["default"].wrap(function _callee8$(_context8) {
434
464
  while (1) {
435
- switch (_context7.prev = _context7.next) {
465
+ switch (_context8.prev = _context8.next) {
436
466
  case 0:
437
467
  _this$store3 = this.store, getState = _this$store3.getState, setState = _this$store3.setState;
438
468
  state = getState();
@@ -493,17 +523,17 @@ var Feed = /*#__PURE__*/function () {
493
523
  });
494
524
  }
495
525
 
496
- return _context7.abrupt("return", this.makeStatusUpdate(itemOrItems, "archived"));
526
+ return _context8.abrupt("return", this.makeStatusUpdate(itemOrItems, "archived"));
497
527
 
498
528
  case 7:
499
529
  case "end":
500
- return _context7.stop();
530
+ return _context8.stop();
501
531
  }
502
532
  }
503
- }, _callee7, this);
533
+ }, _callee8, this);
504
534
  }));
505
535
 
506
- function markAsArchived(_x5) {
536
+ function markAsArchived(_x6) {
507
537
  return _markAsArchived.apply(this, arguments);
508
538
  }
509
539
 
@@ -512,12 +542,12 @@ var Feed = /*#__PURE__*/function () {
512
542
  }, {
513
543
  key: "markAllAsArchived",
514
544
  value: function () {
515
- var _markAllAsArchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8() {
545
+ var _markAllAsArchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee9() {
516
546
  var _this$store4, setState, getState, _getState3, items, shouldOptimisticallyRemoveItems, result;
517
547
 
518
- return _regenerator["default"].wrap(function _callee8$(_context8) {
548
+ return _regenerator["default"].wrap(function _callee9$(_context9) {
519
549
  while (1) {
520
- switch (_context8.prev = _context8.next) {
550
+ switch (_context9.prev = _context9.next) {
521
551
  case 0:
522
552
  // Note: there is the potential for a race condition here because the bulk
523
553
  // update is an async method, so if a new message comes in during this window before
@@ -546,25 +576,25 @@ var Feed = /*#__PURE__*/function () {
546
576
  } // Issue the API request to the bulk status change API
547
577
 
548
578
 
549
- _context8.next = 6;
579
+ _context9.next = 6;
550
580
  return this.makeBulkStatusUpdate("archive");
551
581
 
552
582
  case 6:
553
- result = _context8.sent;
583
+ result = _context9.sent;
554
584
  this.broadcaster.emit("items:all_archived", {
555
585
  items: items
556
586
  });
557
587
  this.broadcastOverChannel("items:all_archived", {
558
588
  items: items
559
589
  });
560
- return _context8.abrupt("return", result);
590
+ return _context9.abrupt("return", result);
561
591
 
562
592
  case 10:
563
593
  case "end":
564
- return _context8.stop();
594
+ return _context9.stop();
565
595
  }
566
596
  }
567
- }, _callee8, this);
597
+ }, _callee9, this);
568
598
  }));
569
599
 
570
600
  function markAllAsArchived() {
@@ -576,25 +606,25 @@ var Feed = /*#__PURE__*/function () {
576
606
  }, {
577
607
  key: "markAsUnarchived",
578
608
  value: function () {
579
- var _markAsUnarchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee9(itemOrItems) {
580
- return _regenerator["default"].wrap(function _callee9$(_context9) {
609
+ var _markAsUnarchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10(itemOrItems) {
610
+ return _regenerator["default"].wrap(function _callee10$(_context10) {
581
611
  while (1) {
582
- switch (_context9.prev = _context9.next) {
612
+ switch (_context10.prev = _context10.next) {
583
613
  case 0:
584
614
  this.optimisticallyPerformStatusUpdate(itemOrItems, "unarchived", {
585
615
  archived_at: null
586
616
  });
587
- return _context9.abrupt("return", this.makeStatusUpdate(itemOrItems, "unarchived"));
617
+ return _context10.abrupt("return", this.makeStatusUpdate(itemOrItems, "unarchived"));
588
618
 
589
619
  case 2:
590
620
  case "end":
591
- return _context9.stop();
621
+ return _context10.stop();
592
622
  }
593
623
  }
594
- }, _callee9, this);
624
+ }, _callee10, this);
595
625
  }));
596
626
 
597
- function markAsUnarchived(_x6) {
627
+ function markAsUnarchived(_x7) {
598
628
  return _markAsUnarchived.apply(this, arguments);
599
629
  }
600
630
 
@@ -605,7 +635,7 @@ var Feed = /*#__PURE__*/function () {
605
635
  }, {
606
636
  key: "fetch",
607
637
  value: function () {
608
- var _fetch = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10() {
638
+ var _fetch = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11() {
609
639
  var options,
610
640
  _this$store5,
611
641
  setState,
@@ -619,22 +649,22 @@ var Feed = /*#__PURE__*/function () {
619
649
  _opts,
620
650
  feedEventType,
621
651
  eventPayload,
622
- _args10 = arguments;
652
+ _args11 = arguments;
623
653
 
624
- return _regenerator["default"].wrap(function _callee10$(_context10) {
654
+ return _regenerator["default"].wrap(function _callee11$(_context11) {
625
655
  while (1) {
626
- switch (_context10.prev = _context10.next) {
656
+ switch (_context11.prev = _context11.next) {
627
657
  case 0:
628
- options = _args10.length > 0 && _args10[0] !== undefined ? _args10[0] : {};
658
+ options = _args11.length > 0 && _args11[0] !== undefined ? _args11[0] : {};
629
659
  _this$store5 = this.store, setState = _this$store5.setState, getState = _this$store5.getState;
630
660
  _getState4 = getState(), networkStatus = _getState4.networkStatus; // If there's an existing request in flight, then do nothing
631
661
 
632
662
  if (!(0, _networkStatus.isRequestInFlight)(networkStatus)) {
633
- _context10.next = 5;
663
+ _context11.next = 5;
634
664
  break;
635
665
  }
636
666
 
637
- return _context10.abrupt("return");
667
+ return _context11.abrupt("return");
638
668
 
639
669
  case 5:
640
670
  // Set the loading type based on the request type it is
@@ -650,7 +680,7 @@ var Feed = /*#__PURE__*/function () {
650
680
  __fetchSource: undefined,
651
681
  __experimentalCrossBrowserUpdates: undefined
652
682
  });
653
- _context10.next = 9;
683
+ _context11.next = 9;
654
684
  return this.apiClient.makeRequest({
655
685
  method: "GET",
656
686
  url: "/v1/users/".concat(this.knock.userId, "/feeds/").concat(this.feedId),
@@ -658,17 +688,17 @@ var Feed = /*#__PURE__*/function () {
658
688
  });
659
689
 
660
690
  case 9:
661
- result = _context10.sent;
691
+ result = _context11.sent;
662
692
 
663
693
  if (!(result.statusCode === "error" || !result.body)) {
664
- _context10.next = 13;
694
+ _context11.next = 13;
665
695
  break;
666
696
  }
667
697
 
668
698
  setState(function (store) {
669
699
  return store.setNetworkStatus(_networkStatus.NetworkStatus.error);
670
700
  });
671
- return _context10.abrupt("return", {
701
+ return _context11.abrupt("return", {
672
702
  status: result.statusCode,
673
703
  data: result.error || result.body
674
704
  });
@@ -712,17 +742,17 @@ var Feed = /*#__PURE__*/function () {
712
742
  event: feedEventType
713
743
  };
714
744
  this.broadcast(eventPayload.event, eventPayload);
715
- return _context10.abrupt("return", {
745
+ return _context11.abrupt("return", {
716
746
  data: response,
717
747
  status: result.statusCode
718
748
  });
719
749
 
720
750
  case 20:
721
751
  case "end":
722
- return _context10.stop();
752
+ return _context11.stop();
723
753
  }
724
754
  }
725
- }, _callee10, this);
755
+ }, _callee11, this);
726
756
  }));
727
757
 
728
758
  function fetch() {
@@ -734,23 +764,23 @@ var Feed = /*#__PURE__*/function () {
734
764
  }, {
735
765
  key: "fetchNextPage",
736
766
  value: function () {
737
- var _fetchNextPage = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11() {
767
+ var _fetchNextPage = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12() {
738
768
  var getState, _getState5, pageInfo;
739
769
 
740
- return _regenerator["default"].wrap(function _callee11$(_context11) {
770
+ return _regenerator["default"].wrap(function _callee12$(_context12) {
741
771
  while (1) {
742
- switch (_context11.prev = _context11.next) {
772
+ switch (_context12.prev = _context12.next) {
743
773
  case 0:
744
774
  // Attempts to fetch the next page of results (if we have any)
745
775
  getState = this.store.getState;
746
776
  _getState5 = getState(), pageInfo = _getState5.pageInfo;
747
777
 
748
778
  if (pageInfo.after) {
749
- _context11.next = 4;
779
+ _context12.next = 4;
750
780
  break;
751
781
  }
752
782
 
753
- return _context11.abrupt("return");
783
+ return _context12.abrupt("return");
754
784
 
755
785
  case 4:
756
786
  this.fetch({
@@ -760,10 +790,10 @@ var Feed = /*#__PURE__*/function () {
760
790
 
761
791
  case 5:
762
792
  case "end":
763
- return _context11.stop();
793
+ return _context12.stop();
764
794
  }
765
795
  }
766
- }, _callee11, this);
796
+ }, _callee12, this);
767
797
  }));
768
798
 
769
799
  function fetchNextPage() {
@@ -781,12 +811,12 @@ var Feed = /*#__PURE__*/function () {
781
811
  }, {
782
812
  key: "onNewMessageReceived",
783
813
  value: function () {
784
- var _onNewMessageReceived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12(_ref) {
814
+ var _onNewMessageReceived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee13(_ref) {
785
815
  var metadata, _this$store6, getState, setState, _getState6, items, currentHead;
786
816
 
787
- return _regenerator["default"].wrap(function _callee12$(_context12) {
817
+ return _regenerator["default"].wrap(function _callee13$(_context13) {
788
818
  while (1) {
789
- switch (_context12.prev = _context12.next) {
819
+ switch (_context13.prev = _context13.next) {
790
820
  case 0:
791
821
  metadata = _ref.metadata;
792
822
  // Handle the new message coming in
@@ -805,13 +835,13 @@ var Feed = /*#__PURE__*/function () {
805
835
 
806
836
  case 6:
807
837
  case "end":
808
- return _context12.stop();
838
+ return _context13.stop();
809
839
  }
810
840
  }
811
- }, _callee12, this);
841
+ }, _callee13, this);
812
842
  }));
813
843
 
814
- function onNewMessageReceived(_x7) {
844
+ function onNewMessageReceived(_x8) {
815
845
  return _onNewMessageReceived.apply(this, arguments);
816
846
  }
817
847
 
@@ -852,18 +882,18 @@ var Feed = /*#__PURE__*/function () {
852
882
  }, {
853
883
  key: "makeStatusUpdate",
854
884
  value: function () {
855
- var _makeStatusUpdate = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee13(itemOrItems, type) {
885
+ var _makeStatusUpdate = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee14(itemOrItems, type) {
856
886
  var items, itemIds, result;
857
- return _regenerator["default"].wrap(function _callee13$(_context13) {
887
+ return _regenerator["default"].wrap(function _callee14$(_context14) {
858
888
  while (1) {
859
- switch (_context13.prev = _context13.next) {
889
+ switch (_context14.prev = _context14.next) {
860
890
  case 0:
861
891
  // Always treat items as a batch to use the corresponding batch endpoint
862
892
  items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
863
893
  itemIds = items.map(function (item) {
864
894
  return item.id;
865
895
  });
866
- _context13.next = 4;
896
+ _context14.next = 4;
867
897
  return this.apiClient.makeRequest({
868
898
  method: "POST",
869
899
  url: "/v1/messages/batch/".concat(type),
@@ -873,7 +903,7 @@ var Feed = /*#__PURE__*/function () {
873
903
  });
874
904
 
875
905
  case 4:
876
- result = _context13.sent;
906
+ result = _context14.sent;
877
907
  // Emit the event that these items had their statuses changed
878
908
  // Note: we do this after the update to ensure that the server event actually completed
879
909
  this.broadcaster.emit("items:".concat(type), {
@@ -882,17 +912,17 @@ var Feed = /*#__PURE__*/function () {
882
912
  this.broadcastOverChannel("items:".concat(type), {
883
913
  items: items
884
914
  });
885
- return _context13.abrupt("return", result);
915
+ return _context14.abrupt("return", result);
886
916
 
887
917
  case 8:
888
918
  case "end":
889
- return _context13.stop();
919
+ return _context14.stop();
890
920
  }
891
921
  }
892
- }, _callee13, this);
922
+ }, _callee14, this);
893
923
  }));
894
924
 
895
- function makeStatusUpdate(_x8, _x9) {
925
+ function makeStatusUpdate(_x9, _x10) {
896
926
  return _makeStatusUpdate.apply(this, arguments);
897
927
  }
898
928
 
@@ -901,11 +931,11 @@ var Feed = /*#__PURE__*/function () {
901
931
  }, {
902
932
  key: "makeBulkStatusUpdate",
903
933
  value: function () {
904
- var _makeBulkStatusUpdate = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee14(type) {
934
+ var _makeBulkStatusUpdate = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee15(type) {
905
935
  var options;
906
- return _regenerator["default"].wrap(function _callee14$(_context14) {
936
+ return _regenerator["default"].wrap(function _callee15$(_context15) {
907
937
  while (1) {
908
- switch (_context14.prev = _context14.next) {
938
+ switch (_context15.prev = _context15.next) {
909
939
  case 0:
910
940
  // The base scope for the call should take into account all of the options currently
911
941
  // set on the feed, as well as being scoped for the current user. We do this so that
@@ -918,7 +948,7 @@ var Feed = /*#__PURE__*/function () {
918
948
  has_tenant: this.defaultOptions.has_tenant,
919
949
  tenants: this.defaultOptions.tenant ? [this.defaultOptions.tenant] : undefined
920
950
  };
921
- _context14.next = 3;
951
+ _context15.next = 3;
922
952
  return this.apiClient.makeRequest({
923
953
  method: "POST",
924
954
  url: "/v1/channels/".concat(this.feedId, "/messages/bulk/").concat(type),
@@ -926,17 +956,17 @@ var Feed = /*#__PURE__*/function () {
926
956
  });
927
957
 
928
958
  case 3:
929
- return _context14.abrupt("return", _context14.sent);
959
+ return _context15.abrupt("return", _context15.sent);
930
960
 
931
961
  case 4:
932
962
  case "end":
933
- return _context14.stop();
963
+ return _context15.stop();
934
964
  }
935
965
  }
936
- }, _callee14, this);
966
+ }, _callee15, this);
937
967
  }));
938
968
 
939
- function makeBulkStatusUpdate(_x10) {
969
+ function makeBulkStatusUpdate(_x11) {
940
970
  return _makeBulkStatusUpdate.apply(this, arguments);
941
971
  }
942
972
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/clients/feed/feed.ts"],"names":["feedClientDefaults","archived","Feed","knock","feedId","options","apiClient","client","userFeedId","buildUserFeedId","store","broadcaster","EventEmitter","wildcard","delimiter","defaultOptions","channel","socket","on","resp","onNewMessageReceived","broadcastChannel","self","BroadcastChannel","leave","removeAllListeners","off","destroy","close","isConnected","connect","includes","state","join","__experimentalCrossBrowserUpdates","onmessage","e","data","type","fetch","eventName","callback","getState","itemOrItems","now","Date","toISOString","optimisticallyPerformStatusUpdate","seen_at","makeStatusUpdate","setState","metadata","items","isViewingOnlyUnseen","status","resetStore","total_count","unseen_count","setMetadata","attrs","itemIds","map","item","id","setItemAttrs","makeBulkStatusUpdate","result","emit","broadcastOverChannel","read_at","isViewingOnlyUnread","unread_count","shouldOptimisticallyRemoveItems","normalizedItems","Array","isArray","unseenCount","filter","i","length","unreadCount","updatedMetadata","entriesToSet","setResult","entries","meta","page_info","pageInfo","archived_at","networkStatus","setNetworkStatus","__loadingType","NetworkStatus","loading","queryParams","undefined","__fetchSource","makeRequest","method","url","userId","params","statusCode","body","error","response","before","opts","shouldSetPage","shouldAppend","after","broadcast","feedEventType","eventPayload","event","fetchMore","currentHead","__cursor","badgeCountAttr","direction","startsWith","Math","max","message_ids","user_ids","engagement_status","has_tenant","tenants","tenant","payload","stringifiedPayload","JSON","parse","stringify","postMessage","console","warn"],"mappings":";;;;;;;;;;;;;;;;;;;AAEA;;AAEA;;AAmBA;;;;;;AAUA;AACA,IAAMA,kBAAuD,GAAG;AAC9DC,EAAAA,QAAQ,EAAE;AADoD,CAAhE;;IAIMC,I;AAQJ;AAGA,gBACWC,KADX,EAEWC,MAFX,EAGEC,OAHF,EAIE;AAAA;;AAAA;AAAA,SAHSF,KAGT,GAHSA,KAGT;AAAA,SAFSC,MAET,GAFSA,MAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,SAAKE,SAAL,GAAiBH,KAAK,CAACI,MAAN,EAAjB;AACA,SAAKH,MAAL,GAAcA,MAAd;AACA,SAAKI,UAAL,GAAkB,KAAKC,eAAL,EAAlB;AACA,SAAKC,KAAL,GAAa,wBAAb;AACA,SAAKC,WAAL,GAAmB,IAAIC,2BAAJ,CAAiB;AAAEC,MAAAA,QAAQ,EAAE,IAAZ;AAAkBC,MAAAA,SAAS,EAAE;AAA7B,KAAjB,CAAnB;AACA,SAAKC,cAAL,mCAA2Bf,kBAA3B,GAAkDK,OAAlD;AAEA,SAAKW,OAAL,GAAe,KAAKV,SAAL,CAAeW,MAAf,CAAsBD,OAAtB,iBACJ,KAAKR,UADD,GAEb,KAAKO,cAFQ,CAAf;AAKA,SAAKC,OAAL,CAAaE,EAAb,CAAgB,aAAhB,EAA+B,UAACC,IAAD;AAAA,aAAU,KAAI,CAACC,oBAAL,CAA0BD,IAA1B,CAAV;AAAA,KAA/B,EAbA,CAeA;AACA;;AACA,SAAKE,gBAAL,GACEC,IAAI,IAAI,sBAAsBA,IAA9B,GACI,IAAIC,gBAAJ,sBAAmC,KAAKf,UAAxC,EADJ,GAEI,IAHN;AAID;AAED;AACF;AACA;AACA;;;;;WACE,oBAAW;AACT,WAAKQ,OAAL,CAAaQ,KAAb;AACA,WAAKb,WAAL,CAAiBc,kBAAjB;AACA,WAAKT,OAAL,CAAaU,GAAb,CAAiB,aAAjB;AACA,WAAKhB,KAAL,CAAWiB,OAAX;;AAEA,UAAI,KAAKN,gBAAT,EAA2B;AACzB,aAAKA,gBAAL,CAAsBO,KAAtB;AACD;AACF;AAED;AACF;AACA;AACA;;;;WACE,4BAAmB;AAAA;;AACjB;AACA,UAAI,CAAC,KAAKtB,SAAL,CAAeW,MAAf,CAAsBY,WAAtB,EAAL,EAA0C;AACxC,aAAKvB,SAAL,CAAeW,MAAf,CAAsBa,OAAtB;AACD,OAJgB,CAMjB;;;AACA,UAAI,CAAC,QAAD,EAAW,SAAX,EAAsBC,QAAtB,CAA+B,KAAKf,OAAL,CAAagB,KAA5C,CAAJ,EAAwD;AACtD,aAAKhB,OAAL,CAAaiB,IAAb;AACD,OATgB,CAWjB;AACA;;;AACA,UACE,KAAKZ,gBAAL,IACA,KAAKN,cAAL,CAAoBmB,iCAApB,KAA0D,IAF5D,EAGE;AACA,aAAKb,gBAAL,CAAsBc,SAAtB,GAAkC,UAACC,CAAD,EAAO;AACvC,kBAAQA,CAAC,CAACC,IAAF,CAAOC,IAAf;AACE,iBAAK,gBAAL;AACA,iBAAK,kBAAL;AACA,iBAAK,YAAL;AACA,iBAAK,cAAL;AACA,iBAAK,YAAL;AACA,iBAAK,cAAL;AACA,iBAAK,gBAAL;AACA,iBAAK,gBAAL;AACA,iBAAK,oBAAL;AACE;AACA;AACA;AACA,qBAAO,MAAI,CAACC,KAAL,EAAP;AACA;;AACF;AACE,qBAAO,IAAP;AAhBJ;AAkBD,SAnBD;AAoBD;AACF;AAED;;;;WACA,YACEC,SADF,EAEEC,QAFF,EAGE;AACA,WAAK9B,WAAL,CAAiBO,EAAjB,CAAoBsB,SAApB,EAA+BC,QAA/B;AACD;;;WAED,aACED,SADF,EAEEC,QAFF,EAGE;AACA,WAAK9B,WAAL,CAAiBe,GAAjB,CAAqBc,SAArB,EAAgCC,QAAhC;AACD;;;WAED,oBAAW;AACT,aAAO,KAAK/B,KAAL,CAAWgC,QAAX,EAAP;AACD;;;;sGAED,iBAAiBC,WAAjB;AAAA;AAAA;AAAA;AAAA;AAAA;AACQC,gBAAAA,GADR,GACc,IAAIC,IAAJ,GAAWC,WAAX,EADd;AAEE,qBAAKC,iCAAL,CACEJ,WADF,EAEE,MAFF,EAGE;AAAEK,kBAAAA,OAAO,EAAEJ;AAAX,iBAHF,EAIE,cAJF;AAFF,iDASS,KAAKK,gBAAL,CAAsBN,WAAtB,EAAmC,MAAnC,CATT;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;yGAYA;AAAA;;AAAA;AAAA;AAAA;AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAXF,8BAYiC,KAAKjC,KAZtC,EAYUgC,QAZV,eAYUA,QAZV,EAYoBQ,QAZpB,eAYoBA,QAZpB;AAAA,4BAa8BR,QAAQ,EAbtC,EAaUS,QAbV,aAaUA,QAbV,EAaoBC,KAbpB,aAaoBA,KAbpB;AAeQC,gBAAAA,mBAfR,GAe8B,KAAKtC,cAAL,CAAoBuC,MAApB,KAA+B,QAf7D,EAiBE;AACA;AACA;;AACA,oBAAID,mBAAJ,EAAyB;AACvBH,kBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,2BACPA,KAAK,CAAC6C,UAAN,iCACKJ,QADL;AAEEK,sBAAAA,WAAW,EAAE,CAFf;AAGEC,sBAAAA,YAAY,EAAE;AAHhB,uBADO;AAAA,mBAAD,CAAR;AAOD,iBARD,MAQO;AACL;AACAP,kBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,2BAAWA,KAAK,CAACgD,WAAN,iCAAuBP,QAAvB;AAAiCM,sBAAAA,YAAY,EAAE;AAA/C,uBAAX;AAAA,mBAAD,CAAR;AAEME,kBAAAA,KAJD,GAIS;AAAEX,oBAAAA,OAAO,EAAE,IAAIH,IAAJ,GAAWC,WAAX;AAAX,mBAJT;AAKCc,kBAAAA,OALD,GAKWR,KAAK,CAACS,GAAN,CAAU,UAACC,IAAD;AAAA,2BAAUA,IAAI,CAACC,EAAf;AAAA,mBAAV,CALX;AAOLb,kBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,2BAAWA,KAAK,CAACsD,YAAN,CAAmBJ,OAAnB,EAA4BD,KAA5B,CAAX;AAAA,mBAAD,CAAR;AACD,iBApCH,CAsCE;;;AAtCF;AAAA,uBAuCuB,KAAKM,oBAAL,CAA0B,MAA1B,CAvCvB;;AAAA;AAuCQC,gBAAAA,MAvCR;AAyCE,qBAAKvD,WAAL,CAAiBwD,IAAjB,mBAAwC;AAAEf,kBAAAA,KAAK,EAALA;AAAF,iBAAxC;AACA,qBAAKgB,oBAAL,mBAA4C;AAAEhB,kBAAAA,KAAK,EAALA;AAAF,iBAA5C;AA1CF,kDA4CSc,MA5CT;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;wGA+CA,kBAAmBvB,WAAnB;AAAA;AAAA;AAAA;AAAA;AACE,qBAAKI,iCAAL,CACEJ,WADF,EAEE,QAFF,EAGE;AAAEK,kBAAAA,OAAO,EAAE;AAAX,iBAHF,EAIE,cAJF;AADF,kDAQS,KAAKC,gBAAL,CAAsBN,WAAtB,EAAmC,QAAnC,CART;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;sGAWA,kBAAiBA,WAAjB;AAAA;AAAA;AAAA;AAAA;AAAA;AACQC,gBAAAA,GADR,GACc,IAAIC,IAAJ,GAAWC,WAAX,EADd;AAEE,qBAAKC,iCAAL,CACEJ,WADF,EAEE,MAFF,EAGE;AAAE0B,kBAAAA,OAAO,EAAEzB;AAAX,iBAHF,EAIE,cAJF;AAFF,kDASS,KAAKK,gBAAL,CAAsBN,WAAtB,EAAmC,MAAnC,CATT;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;yGAYA;AAAA;;AAAA;AAAA;AAAA;AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAXF,+BAYiC,KAAKjC,KAZtC,EAYUgC,QAZV,gBAYUA,QAZV,EAYoBQ,QAZpB,gBAYoBA,QAZpB;AAAA,6BAa8BR,QAAQ,EAbtC,EAaUS,QAbV,cAaUA,QAbV,EAaoBC,KAbpB,cAaoBA,KAbpB;AAeQkB,gBAAAA,mBAfR,GAe8B,KAAKvD,cAAL,CAAoBuC,MAApB,KAA+B,QAf7D,EAiBE;AACA;AACA;;AACA,oBAAIgB,mBAAJ,EAAyB;AACvBpB,kBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,2BACPA,KAAK,CAAC6C,UAAN,iCACKJ,QADL;AAEEK,sBAAAA,WAAW,EAAE,CAFf;AAGEe,sBAAAA,YAAY,EAAE;AAHhB,uBADO;AAAA,mBAAD,CAAR;AAOD,iBARD,MAQO;AACL;AACArB,kBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,2BAAWA,KAAK,CAACgD,WAAN,iCAAuBP,QAAvB;AAAiCoB,sBAAAA,YAAY,EAAE;AAA/C,uBAAX;AAAA,mBAAD,CAAR;AAEMZ,kBAAAA,KAJD,GAIS;AAAEU,oBAAAA,OAAO,EAAE,IAAIxB,IAAJ,GAAWC,WAAX;AAAX,mBAJT;AAKCc,kBAAAA,OALD,GAKWR,KAAK,CAACS,GAAN,CAAU,UAACC,IAAD;AAAA,2BAAUA,IAAI,CAACC,EAAf;AAAA,mBAAV,CALX;AAOLb,kBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,2BAAWA,KAAK,CAACsD,YAAN,CAAmBJ,OAAnB,EAA4BD,KAA5B,CAAX;AAAA,mBAAD,CAAR;AACD,iBApCH,CAsCE;;;AAtCF;AAAA,uBAuCuB,KAAKM,oBAAL,CAA0B,MAA1B,CAvCvB;;AAAA;AAuCQC,gBAAAA,MAvCR;AAyCE,qBAAKvD,WAAL,CAAiBwD,IAAjB,mBAAwC;AAAEf,kBAAAA,KAAK,EAALA;AAAF,iBAAxC;AACA,qBAAKgB,oBAAL,mBAA4C;AAAEhB,kBAAAA,KAAK,EAALA;AAAF,iBAA5C;AA1CF,kDA4CSc,MA5CT;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;wGA+CA,kBAAmBvB,WAAnB;AAAA;AAAA;AAAA;AAAA;AACE,qBAAKI,iCAAL,CACEJ,WADF,EAEE,QAFF,EAGE;AAAE0B,kBAAAA,OAAO,EAAE;AAAX,iBAHF,EAIE,cAJF;AADF,kDAQS,KAAKpB,gBAAL,CAAsBN,WAAtB,EAAmC,QAAnC,CART;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;AAWA;AACF;AACA;AACA;AACA;AACA;;;;;0GAGE,kBAAqBA,WAArB;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,+BACiC,KAAKjC,KADtC,EACUgC,QADV,gBACUA,QADV,EACoBQ,QADpB,gBACoBA,QADpB;AAEQlB,gBAAAA,KAFR,GAEgBU,QAAQ,EAFxB;AAIQ8B,gBAAAA,+BAJR,GAKI,KAAKzD,cAAL,CAAoBd,QAApB,KAAiC,SALrC;AAOQwE,gBAAAA,eAPR,GAO0BC,KAAK,CAACC,OAAN,CAAchC,WAAd,IACpBA,WADoB,GAEpB,CAACA,WAAD,CATN;AAWQiB,gBAAAA,OAXR,GAW4Ba,eAAe,CAACZ,GAAhB,CAAoB,UAACC,IAAD;AAAA,yBAAUA,IAAI,CAACC,EAAf;AAAA,iBAApB,CAX5B;AAaE;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAUI,oBAAIS,+BAAJ,EAAqC;AACnC;AACA;AACMI,kBAAAA,WAH6B,GAGfH,eAAe,CAACI,MAAhB,CAAuB,UAACC,CAAD;AAAA,2BAAO,CAACA,CAAC,CAAC9B,OAAV;AAAA,mBAAvB,EAA0C+B,MAH3B;AAI7BC,kBAAAA,WAJ6B,GAIfP,eAAe,CAACI,MAAhB,CAAuB,UAACC,CAAD;AAAA,2BAAO,CAACA,CAAC,CAACT,OAAV;AAAA,mBAAvB,EAA0CU,MAJ3B,EAMnC;;AACME,kBAAAA,eAP6B,mCAQ9BjD,KAAK,CAACmB,QARwB;AASjCK,oBAAAA,WAAW,EAAExB,KAAK,CAACmB,QAAN,CAAeK,WAAf,GAA6BiB,eAAe,CAACM,MATzB;AAUjCtB,oBAAAA,YAAY,EAAEzB,KAAK,CAACmB,QAAN,CAAeM,YAAf,GAA8BmB,WAVX;AAWjCL,oBAAAA,YAAY,EAAEvC,KAAK,CAACmB,QAAN,CAAeoB,YAAf,GAA8BS;AAXX,sBAcnC;;AACME,kBAAAA,YAf6B,GAedlD,KAAK,CAACoB,KAAN,CAAYyB,MAAZ,CACnB,UAACf,IAAD;AAAA,2BAAU,CAACF,OAAO,CAAC7B,QAAR,CAAiB+B,IAAI,CAACC,EAAtB,CAAX;AAAA,mBADmB,CAfc;AAmBnCb,kBAAAA,QAAQ,CAAC,UAAClB,KAAD;AAAA,2BACPA,KAAK,CAACmD,SAAN,CAAgB;AACdC,sBAAAA,OAAO,EAAEF,YADK;AAEdG,sBAAAA,IAAI,EAAEJ,eAFQ;AAGdK,sBAAAA,SAAS,EAAEtD,KAAK,CAACuD;AAHH,qBAAhB,CADO;AAAA,mBAAD,CAAR;AAOD,iBA1BD,MA0BO;AACL;AACAvD,kBAAAA,KAAK,CAACgC,YAAN,CAAmBJ,OAAnB,EAA4B;AAAE4B,oBAAAA,WAAW,EAAE,IAAI3C,IAAJ,GAAWC,WAAX;AAAf,mBAA5B;AACD;;AArEH,kDAuES,KAAKG,gBAAL,CAAsBN,WAAtB,EAAmC,UAAnC,CAvET;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;6GA0EA;AAAA;;AAAA;AAAA;AAAA;AAAA;AACE;AACA;AACA;AAHF,+BAIiC,KAAKjC,KAJtC,EAIUwC,QAJV,gBAIUA,QAJV,EAIoBR,QAJpB,gBAIoBA,QAJpB;AAAA,6BAKoBA,QAAQ,EAL5B,EAKUU,KALV,cAKUA,KALV,EAOE;AACA;;AACMoB,gBAAAA,+BATR,GAUI,KAAKzD,cAAL,CAAoBd,QAApB,KAAiC,SAVrC;;AAYE,oBAAIuE,+BAAJ,EAAqC;AACnC;AACAtB,kBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,2BAAWA,KAAK,CAAC6C,UAAN,EAAX;AAAA,mBAAD,CAAR;AACD,iBAHD,MAGO;AACL;AACAL,kBAAAA,QAAQ,CAAC,UAACxC,KAAD,EAAW;AAClB,wBAAMkD,OAAO,GAAGR,KAAK,CAACS,GAAN,CAAU,UAACiB,CAAD;AAAA,6BAAOA,CAAC,CAACf,EAAT;AAAA,qBAAV,CAAhB;AACArD,oBAAAA,KAAK,CAACsD,YAAN,CAAmBJ,OAAnB,EAA4B;AAAE4B,sBAAAA,WAAW,EAAE,IAAI3C,IAAJ,GAAWC,WAAX;AAAf,qBAA5B;AACD,mBAHO,CAAR;AAID,iBArBH,CAuBE;;;AAvBF;AAAA,uBAwBuB,KAAKmB,oBAAL,CAA0B,SAA1B,CAxBvB;;AAAA;AAwBQC,gBAAAA,MAxBR;AA0BE,qBAAKvD,WAAL,CAAiBwD,IAAjB,uBAA4C;AAAEf,kBAAAA,KAAK,EAALA;AAAF,iBAA5C;AACA,qBAAKgB,oBAAL,uBAAgD;AAAEhB,kBAAAA,KAAK,EAALA;AAAF,iBAAhD;AA3BF,kDA6BSc,MA7BT;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;4GAgCA,kBAAuBvB,WAAvB;AAAA;AAAA;AAAA;AAAA;AACE,qBAAKI,iCAAL,CAAuCJ,WAAvC,EAAoD,YAApD,EAAkE;AAChE6C,kBAAAA,WAAW,EAAE;AADmD,iBAAlE;AADF,kDAKS,KAAKvC,gBAAL,CAAsBN,WAAtB,EAAmC,YAAnC,CALT;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;AAQA;;;;;iGACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAYtC,gBAAAA,OAAZ,iEAAwC,EAAxC;AAAA,+BACiC,KAAKK,KADtC,EACUwC,QADV,gBACUA,QADV,EACoBR,QADpB,gBACoBA,QADpB;AAAA,6BAE4BA,QAAQ,EAFpC,EAEU+C,aAFV,cAEUA,aAFV,EAIE;;AAJF,qBAKM,sCAAkBA,aAAlB,CALN;AAAA;AAAA;AAAA;;AAAA;;AAAA;AASE;AACAvC,gBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA;;AAAA,yBACPA,KAAK,CAACgF,gBAAN,0BAAuBrF,OAAO,CAACsF,aAA/B,yEAAgDC,6BAAcC,OAA9D,CADO;AAAA,iBAAD,CAAR,CAVF,CAcE;;AACMC,gBAAAA,WAfR,iDAgBO,KAAK/E,cAhBZ,GAiBOV,OAjBP;AAkBI;AACAsF,kBAAAA,aAAa,EAAEI,SAnBnB;AAoBIC,kBAAAA,aAAa,EAAED,SApBnB;AAqBI7D,kBAAAA,iCAAiC,EAAE6D;AArBvC;AAAA;AAAA,uBAwBuB,KAAKzF,SAAL,CAAe2F,WAAf,CAA2B;AAC9CC,kBAAAA,MAAM,EAAE,KADsC;AAE9CC,kBAAAA,GAAG,sBAAe,KAAKhG,KAAL,CAAWiG,MAA1B,oBAA0C,KAAKhG,MAA/C,CAF2C;AAG9CiG,kBAAAA,MAAM,EAAEP;AAHsC,iBAA3B,CAxBvB;;AAAA;AAwBQ5B,gBAAAA,MAxBR;;AAAA,sBA8BMA,MAAM,CAACoC,UAAP,KAAsB,OAAtB,IAAiC,CAACpC,MAAM,CAACqC,IA9B/C;AAAA;AAAA;AAAA;;AA+BIrD,gBAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,yBAAWA,KAAK,CAACgF,gBAAN,CAAuBE,6BAAcY,KAArC,CAAX;AAAA,iBAAD,CAAR;AA/BJ,mDAiCW;AACLlD,kBAAAA,MAAM,EAAEY,MAAM,CAACoC,UADV;AAELjE,kBAAAA,IAAI,EAAE6B,MAAM,CAACsC,KAAP,IAAgBtC,MAAM,CAACqC;AAFxB,iBAjCX;;AAAA;AAuCQE,gBAAAA,QAvCR,GAuCmB;AACfrB,kBAAAA,OAAO,EAAElB,MAAM,CAACqC,IAAP,CAAYnB,OADN;AAEfC,kBAAAA,IAAI,EAAEnB,MAAM,CAACqC,IAAP,CAAYlB,IAFH;AAGfC,kBAAAA,SAAS,EAAEpB,MAAM,CAACqC,IAAP,CAAYjB;AAHR,iBAvCnB;;AA6CE,oBAAIjF,OAAO,CAACqG,MAAZ,EAAoB;AACZC,kBAAAA,IADY,GACL;AAAEC,oBAAAA,aAAa,EAAE,KAAjB;AAAwBC,oBAAAA,YAAY,EAAE;AAAtC,mBADK;AAElB3D,kBAAAA,QAAQ,CAAC,UAAClB,KAAD;AAAA,2BAAWA,KAAK,CAACmD,SAAN,CAAgBsB,QAAhB,EAA0BE,IAA1B,CAAX;AAAA,mBAAD,CAAR;AACD,iBAHD,MAGO,IAAItG,OAAO,CAACyG,KAAZ,EAAmB;AAClBH,kBAAAA,KADkB,GACX;AAAEC,oBAAAA,aAAa,EAAE,IAAjB;AAAuBC,oBAAAA,YAAY,EAAE;AAArC,mBADW;AAExB3D,kBAAAA,QAAQ,CAAC,UAAClB,KAAD;AAAA,2BAAWA,KAAK,CAACmD,SAAN,CAAgBsB,QAAhB,EAA0BE,KAA1B,CAAX;AAAA,mBAAD,CAAR;AACD,iBAHM,MAGA;AACLzD,kBAAAA,QAAQ,CAAC,UAAClB,KAAD;AAAA,2BAAWA,KAAK,CAACmD,SAAN,CAAgBsB,QAAhB,CAAX;AAAA,mBAAD,CAAR;AACD,iBArDH,CAuDE;;;AACA,qBAAKM,SAAL,CAAe,cAAf,EAA+BN,QAA/B,EAxDF,CA0DE;;AACMO,gBAAAA,aA3DR,GA4DI3G,OAAO,CAAC2F,aAAR,KAA0B,QAA1B,GACI,yBADJ,GAEI,qBA9DR;AAgEQiB,gBAAAA,YAhER,GAgEuB;AACnB7D,kBAAAA,KAAK,EAAEqD,QAAQ,CAACrB,OADG;AAEnBjC,kBAAAA,QAAQ,EAAEsD,QAAQ,CAACpB,IAFA;AAGnB6B,kBAAAA,KAAK,EAAEF;AAHY,iBAhEvB;AAsEE,qBAAKD,SAAL,CAAeE,YAAY,CAACC,KAA5B,EAAmCD,YAAnC;AAtEF,mDAwES;AAAE5E,kBAAAA,IAAI,EAAEoE,QAAR;AAAkBnD,kBAAAA,MAAM,EAAEY,MAAM,CAACoC;AAAjC,iBAxET;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;yGA2EA;AAAA;;AAAA;AAAA;AAAA;AAAA;AACE;AACQ5D,gBAAAA,QAFV,GAEuB,KAAKhC,KAF5B,CAEUgC,QAFV;AAAA,6BAGuBA,QAAQ,EAH/B,EAGU6C,QAHV,cAGUA,QAHV;;AAAA,oBAKOA,QAAQ,CAACuB,KALhB;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAUE,qBAAKvE,KAAL,CAAW;AACTuE,kBAAAA,KAAK,EAAEvB,QAAQ,CAACuB,KADP;AAETnB,kBAAAA,aAAa,EAAEC,6BAAcuB;AAFpB,iBAAX;;AAVF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;WAgBA,mBACE3E,SADF,EAEEH,IAFF,EAGE;AACA,WAAK1B,WAAL,CAAiBwD,IAAjB,CAAsB3B,SAAtB,EAAiCH,IAAjC;AACD,K,CAED;;;;;gHACA;AAAA;;AAAA;AAAA;AAAA;AAAA;AACEc,gBAAAA,QADF,QACEA,QADF;AAGE;AAHF,+BAIiC,KAAKzC,KAJtC,EAIUgC,QAJV,gBAIUA,QAJV,EAIoBQ,QAJpB,gBAIoBA,QAJpB;AAAA,6BAKoBR,QAAQ,EAL5B,EAKUU,KALV,cAKUA,KALV;AAMQgE,gBAAAA,WANR,GAM4ChE,KAAK,CAAC,CAAD,CANjD,EAOE;;AACAF,gBAAAA,QAAQ,CAAC,UAAClB,KAAD;AAAA,yBAAWA,KAAK,CAAC0B,WAAN,CAAkBP,QAAlB,CAAX;AAAA,iBAAD,CAAR,CARF,CASE;;AACA,qBAAKZ,KAAL,CAAW;AAAEmE,kBAAAA,MAAM,EAAEU,WAAF,aAAEA,WAAF,uBAAEA,WAAW,CAAEC,QAAvB;AAAiCrB,kBAAAA,aAAa,EAAE;AAAhD,iBAAX;;AAVF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;WAaA,2BAA0B;AACxB,uBAAU,KAAK5F,MAAf,cAAyB,KAAKD,KAAL,CAAWiG,MAApC;AACD;;;WAED,2CACEzD,WADF,EAEEL,IAFF,EAGEqB,KAHF,EAIE2D,cAJF,EAKE;AACA,yBAA+B,KAAK5G,KAApC;AAAA,UAAQgC,QAAR,gBAAQA,QAAR;AAAA,UAAkBQ,QAAlB,gBAAkBA,QAAlB;AACA,UAAMU,OAAO,GAAGc,KAAK,CAACC,OAAN,CAAchC,WAAd,IACZA,WAAW,CAACkB,GAAZ,CAAgB,UAACC,IAAD;AAAA,eAAUA,IAAI,CAACC,EAAf;AAAA,OAAhB,CADY,GAEZ,CAACpB,WAAW,CAACoB,EAAb,CAFJ;;AAIA,UAAIuD,cAAJ,EAAoB;AAClB,yBAAqB5E,QAAQ,EAA7B;AAAA,YAAQS,QAAR,cAAQA,QAAR,CADkB,CAGlB;AACA;;;AACA,YAAMoE,SAAS,GAAGjF,IAAI,CAACkF,UAAL,CAAgB,IAAhB,IACd5D,OAAO,CAACmB,MADM,GAEd,CAACnB,OAAO,CAACmB,MAFb;AAIA7B,QAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,iBACPA,KAAK,CAACgD,WAAN,iCACKP,QADL,4CAEGmE,cAFH,EAEoBG,IAAI,CAACC,GAAL,CAAS,CAAT,EAAYvE,QAAQ,CAACmE,cAAD,CAAR,GAA2BC,SAAvC,CAFpB,GADO;AAAA,SAAD,CAAR;AAMD,OArBD,CAuBA;;;AACArE,MAAAA,QAAQ,CAAC,UAACxC,KAAD;AAAA,eAAWA,KAAK,CAACsD,YAAN,CAAmBJ,OAAnB,EAA4BD,KAA5B,CAAX;AAAA,OAAD,CAAR;AACD;;;;4GAED,mBAA+BhB,WAA/B,EAA6DL,IAA7D;AAAA;AAAA;AAAA;AAAA;AAAA;AACE;AACMc,gBAAAA,KAFR,GAEgBsB,KAAK,CAACC,OAAN,CAAchC,WAAd,IAA6BA,WAA7B,GAA2C,CAACA,WAAD,CAF3D;AAGQiB,gBAAAA,OAHR,GAGkBR,KAAK,CAACS,GAAN,CAAU,UAACC,IAAD;AAAA,yBAAUA,IAAI,CAACC,EAAf;AAAA,iBAAV,CAHlB;AAAA;AAAA,uBAKuB,KAAKzD,SAAL,CAAe2F,WAAf,CAA2B;AAC9CC,kBAAAA,MAAM,EAAE,MADsC;AAE9CC,kBAAAA,GAAG,+BAAwB7D,IAAxB,CAF2C;AAG9CD,kBAAAA,IAAI,EAAE;AAAEsF,oBAAAA,WAAW,EAAE/D;AAAf;AAHwC,iBAA3B,CALvB;;AAAA;AAKQM,gBAAAA,MALR;AAWE;AACA;AACA,qBAAKvD,WAAL,CAAiBwD,IAAjB,iBAA+B7B,IAA/B,GAAuC;AAAEc,kBAAAA,KAAK,EAALA;AAAF,iBAAvC;AACA,qBAAKgB,oBAAL,iBAAmC9B,IAAnC,GAA2C;AAAEc,kBAAAA,KAAK,EAALA;AAAF,iBAA3C;AAdF,mDAgBSc,MAhBT;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;;gHAmBA,mBAAmC5B,IAAnC;AAAA;AAAA;AAAA;AAAA;AAAA;AACE;AACA;AACA;AACA;AACMjC,gBAAAA,OALR,GAKkB;AACduH,kBAAAA,QAAQ,EAAE,CAAC,KAAKzH,KAAL,CAAWiG,MAAZ,CADI;AAEdyB,kBAAAA,iBAAiB,EACf,KAAK9G,cAAL,CAAoBuC,MAApB,KAA+B,KAA/B,GACI,KAAKvC,cAAL,CAAoBuC,MADxB,GAEIyC,SALQ;AAMd9F,kBAAAA,QAAQ,EAAE,KAAKc,cAAL,CAAoBd,QANhB;AAOd6H,kBAAAA,UAAU,EAAE,KAAK/G,cAAL,CAAoB+G,UAPlB;AAQdC,kBAAAA,OAAO,EAAE,KAAKhH,cAAL,CAAoBiH,MAApB,GACL,CAAC,KAAKjH,cAAL,CAAoBiH,MAArB,CADK,GAELjC;AAVU,iBALlB;AAAA;AAAA,uBAkBe,KAAKzF,SAAL,CAAe2F,WAAf,CAA2B;AACtCC,kBAAAA,MAAM,EAAE,MAD8B;AAEtCC,kBAAAA,GAAG,yBAAkB,KAAK/F,MAAvB,4BAA+CkC,IAA/C,CAFmC;AAGtCD,kBAAAA,IAAI,EAAEhC;AAHgC,iBAA3B,CAlBf;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,O;;;;;;;;;;WAyBA,8BAA6BiC,IAA7B,EAA2C2F,OAA3C,EAAyD;AACvD;AACA,UAAI,CAAC,KAAK5G,gBAAV,EAA4B;AAC1B;AACD,OAJsD,CAMvD;AACA;;;AACA,UAAI;AACF,YAAM6G,kBAAkB,GAAGC,IAAI,CAACC,KAAL,CAAWD,IAAI,CAACE,SAAL,CAAeJ,OAAf,CAAX,CAA3B;AAEA,aAAK5G,gBAAL,CAAsBiH,WAAtB,CAAkC;AAChChG,UAAAA,IAAI,EAAJA,IADgC;AAEhC2F,UAAAA,OAAO,EAAEC;AAFuB,SAAlC;AAID,OAPD,CAOE,OAAO9F,CAAP,EAAU;AACVmG,QAAAA,OAAO,CAACC,IAAR,+BAAoClG,IAApC,0BAAwDF,CAAxD;AACD;AACF;;;;;eAGYlC,I","sourcesContent":["import { Channel } from \"phoenix\";\nimport { StoreApi } from \"zustand\";\nimport { EventEmitter2 as EventEmitter } from \"eventemitter2\";\nimport ApiClient from \"../../api\";\nimport createStore from \"./store\";\nimport {\n BindableFeedEvent,\n FeedMessagesReceivedPayload,\n FeedEventCallback,\n FeedEvent,\n FeedItemOrItems,\n FeedStoreState,\n FeedEventPayload,\n FeedRealTimeCallback,\n} from \"./types\";\nimport {\n FeedItem,\n FeedClientOptions,\n FetchFeedOptions,\n FeedResponse,\n FeedMetadata,\n} from \"./interfaces\";\nimport Knock from \"../../knock\";\nimport { isRequestInFlight, NetworkStatus } from \"../../networkStatus\";\n\nexport type Status =\n | \"seen\"\n | \"read\"\n | \"archived\"\n | \"unseen\"\n | \"unread\"\n | \"unarchived\";\n\n// Default options to apply\nconst feedClientDefaults: Pick<FeedClientOptions, \"archived\"> = {\n archived: \"exclude\",\n};\n\nclass Feed {\n private apiClient: ApiClient;\n private userFeedId: string;\n private channel: Channel;\n private broadcaster: EventEmitter;\n private defaultOptions: FeedClientOptions;\n private broadcastChannel: BroadcastChannel | null;\n\n // The raw store instance, used for binding in React and other environments\n public store: StoreApi<FeedStoreState>;\n\n constructor(\n readonly knock: Knock,\n readonly feedId: string,\n options: FeedClientOptions,\n ) {\n this.apiClient = knock.client();\n this.feedId = feedId;\n this.userFeedId = this.buildUserFeedId();\n this.store = createStore();\n this.broadcaster = new EventEmitter({ wildcard: true, delimiter: \".\" });\n this.defaultOptions = { ...feedClientDefaults, ...options };\n\n this.channel = this.apiClient.socket.channel(\n `feeds:${this.userFeedId}`,\n this.defaultOptions,\n );\n\n this.channel.on(\"new-message\", (resp) => this.onNewMessageReceived(resp));\n\n // Attempt to bind to listen to other events from this feed in different tabs\n // Note: here we ensure `self` is available (it's not in server rendered envs)\n this.broadcastChannel =\n self && \"BroadcastChannel\" in self\n ? new BroadcastChannel(`knock:feed:${this.userFeedId}`)\n : null;\n }\n\n /**\n * Cleans up a feed instance by destroying the store and disconnecting\n * an open socket connection.\n */\n teardown() {\n this.channel.leave();\n this.broadcaster.removeAllListeners();\n this.channel.off(\"new-message\");\n this.store.destroy();\n\n if (this.broadcastChannel) {\n this.broadcastChannel.close();\n }\n }\n\n /*\n Initializes a real-time connection to Knock, connecting the websocket for the\n current ApiClient instance if the socket is not already connected.\n */\n listenForUpdates() {\n // Connect the socket only if we don't already have a connection\n if (!this.apiClient.socket.isConnected()) {\n this.apiClient.socket.connect();\n }\n\n // Only join the channel if we're not already in a joining state\n if ([\"closed\", \"errored\"].includes(this.channel.state)) {\n this.channel.join();\n }\n\n // Opt into receiving updates from _other tabs for the same user / feed_ via the broadcast\n // channel (iff it's enabled and exists)\n if (\n this.broadcastChannel &&\n this.defaultOptions.__experimentalCrossBrowserUpdates === true\n ) {\n this.broadcastChannel.onmessage = (e) => {\n switch (e.data.type) {\n case \"items:archived\":\n case \"items:unarchived\":\n case \"items:seen\":\n case \"items:unseen\":\n case \"items:read\":\n case \"items:unread\":\n case \"items:all_read\":\n case \"items:all_seen\":\n case \"items:all_archived\":\n // When items are updated in any other tab, simply refetch to get the latest state\n // to make sure that the state gets updated accordingly. In the future here we could\n // maybe do this optimistically without the fetch.\n return this.fetch();\n break;\n default:\n return null;\n }\n };\n }\n }\n\n /* Binds a handler to be invoked when event occurs */\n on(\n eventName: BindableFeedEvent,\n callback: FeedEventCallback | FeedRealTimeCallback,\n ) {\n this.broadcaster.on(eventName, callback);\n }\n\n off(\n eventName: BindableFeedEvent,\n callback: FeedEventCallback | FeedRealTimeCallback,\n ) {\n this.broadcaster.off(eventName, callback);\n }\n\n getState() {\n return this.store.getState();\n }\n\n async markAsSeen(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"seen\",\n { seen_at: now },\n \"unseen_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"seen\");\n }\n\n async markAllAsSeen() {\n // To mark all of the messages as seen we:\n // 1. Optimistically update *everything* we have in the store\n // 2. We decrement the `unseen_count` to zero optimistically\n // 3. We issue the API call to the endpoint\n //\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unseen_count` to be what it was.\n //\n // Note: here we optimistically handle the case whereby the feed is scoped to show only `unseen`\n // items by removing everything from view.\n const { getState, setState } = this.store;\n const { metadata, items } = getState();\n\n const isViewingOnlyUnseen = this.defaultOptions.status === \"unseen\";\n\n // If we're looking at the unseen view, then we want to remove all of the items optimistically\n // from the store given that nothing should be visible. We do this by resetting the store state\n // and setting the current metadata counts to 0\n if (isViewingOnlyUnseen) {\n setState((store) =>\n store.resetStore({\n ...metadata,\n total_count: 0,\n unseen_count: 0,\n }),\n );\n } else {\n // Otherwise we want to update the metadata and mark all of the items in the store as seen\n setState((store) => store.setMetadata({ ...metadata, unseen_count: 0 }));\n\n const attrs = { seen_at: new Date().toISOString() };\n const itemIds = items.map((item) => item.id);\n\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"seen\");\n\n this.broadcaster.emit(`items:all_seen`, { items });\n this.broadcastOverChannel(`items:all_seen`, { items });\n\n return result;\n }\n\n async markAsUnseen(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"unseen\",\n { seen_at: null },\n \"unseen_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"unseen\");\n }\n\n async markAsRead(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"read\",\n { read_at: now },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"read\");\n }\n\n async markAllAsRead() {\n // To mark all of the messages as read we:\n // 1. Optimistically update *everything* we have in the store\n // 2. We decrement the `unread_count` to zero optimistically\n // 3. We issue the API call to the endpoint\n //\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unread_count` to be what it was.\n //\n // Note: here we optimistically handle the case whereby the feed is scoped to show only `unread`\n // items by removing everything from view.\n const { getState, setState } = this.store;\n const { metadata, items } = getState();\n\n const isViewingOnlyUnread = this.defaultOptions.status === \"unread\";\n\n // If we're looking at the unread view, then we want to remove all of the items optimistically\n // from the store given that nothing should be visible. We do this by resetting the store state\n // and setting the current metadata counts to 0\n if (isViewingOnlyUnread) {\n setState((store) =>\n store.resetStore({\n ...metadata,\n total_count: 0,\n unread_count: 0,\n }),\n );\n } else {\n // Otherwise we want to update the metadata and mark all of the items in the store as seen\n setState((store) => store.setMetadata({ ...metadata, unread_count: 0 }));\n\n const attrs = { read_at: new Date().toISOString() };\n const itemIds = items.map((item) => item.id);\n\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"read\");\n\n this.broadcaster.emit(`items:all_read`, { items });\n this.broadcastOverChannel(`items:all_read`, { items });\n\n return result;\n }\n\n async markAsUnread(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"unread\",\n { read_at: null },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"unread\");\n }\n\n /*\n Marking one or more items as archived should:\n\n - Decrement the badge count for any unread / unseen items\n - Remove the item from the feed list when the `archived` flag is \"exclude\" (default)\n\n TODO: how do we handle rollbacks?\n */\n async markAsArchived(itemOrItems: FeedItemOrItems) {\n const { getState, setState } = this.store;\n const state = getState();\n\n const shouldOptimisticallyRemoveItems =\n this.defaultOptions.archived === \"exclude\";\n\n const normalizedItems = Array.isArray(itemOrItems)\n ? itemOrItems\n : [itemOrItems];\n\n const itemIds: string[] = normalizedItems.map((item) => item.id);\n\n /*\n In the code here we want to optimistically update counts and items\n that are persisted such that we can display updates immediately on the feed\n without needing to make a network request.\n\n Note: right now this does *not* take into account offline handling or any extensive retry\n logic, so rollbacks aren't considered. That probably needs to be a future consideration for\n this library.\n\n Scenarios to consider:\n\n ## Feed scope to archived *only*\n\n - Counts should not be decremented\n - Items should not be removed\n\n ## Feed scoped to exclude archived items (the default)\n\n - Counts should be decremented\n - Items should be removed\n\n ## Feed scoped to include archived items as well\n\n - Counts should not be decremented\n - Items should not be removed\n */\n\n if (shouldOptimisticallyRemoveItems) {\n // If any of the items are unseen or unread, then capture as we'll want to decrement\n // the counts for these in the metadata we have\n const unseenCount = normalizedItems.filter((i) => !i.seen_at).length;\n const unreadCount = normalizedItems.filter((i) => !i.read_at).length;\n\n // Build the new metadata\n const updatedMetadata = {\n ...state.metadata,\n total_count: state.metadata.total_count - normalizedItems.length,\n unseen_count: state.metadata.unseen_count - unseenCount,\n unread_count: state.metadata.unread_count - unreadCount,\n };\n\n // Remove the archiving entries\n const entriesToSet = state.items.filter(\n (item) => !itemIds.includes(item.id),\n );\n\n setState((state) =>\n state.setResult({\n entries: entriesToSet,\n meta: updatedMetadata,\n page_info: state.pageInfo,\n }),\n );\n } else {\n // Mark all the entries being updated as archived either way so the state is correct\n state.setItemAttrs(itemIds, { archived_at: new Date().toISOString() });\n }\n\n return this.makeStatusUpdate(itemOrItems, \"archived\");\n }\n\n async markAllAsArchived() {\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unseen_count` to be what it was.\n const { setState, getState } = this.store;\n const { items } = getState();\n\n // Here if we're looking at a feed that excludes all of the archived items by default then we\n // will want to optimistically remove all of the items from the feed as they are now all excluded\n const shouldOptimisticallyRemoveItems =\n this.defaultOptions.archived === \"exclude\";\n\n if (shouldOptimisticallyRemoveItems) {\n // Reset the store to clear out all of items and reset the badge count\n setState((store) => store.resetStore());\n } else {\n // Mark all the entries being updated as archived either way so the state is correct\n setState((store) => {\n const itemIds = items.map((i) => i.id);\n store.setItemAttrs(itemIds, { archived_at: new Date().toISOString() });\n });\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"archive\");\n\n this.broadcaster.emit(`items:all_archived`, { items });\n this.broadcastOverChannel(`items:all_archived`, { items });\n\n return result;\n }\n\n async markAsUnarchived(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(itemOrItems, \"unarchived\", {\n archived_at: null,\n });\n\n return this.makeStatusUpdate(itemOrItems, \"unarchived\");\n }\n\n /* Fetches the feed content, appending it to the store */\n async fetch(options: FetchFeedOptions = {}) {\n const { setState, getState } = this.store;\n const { networkStatus } = getState();\n\n // If there's an existing request in flight, then do nothing\n if (isRequestInFlight(networkStatus)) {\n return;\n }\n\n // Set the loading type based on the request type it is\n setState((store) =>\n store.setNetworkStatus(options.__loadingType ?? NetworkStatus.loading),\n );\n\n // Always include the default params, if they have been set\n const queryParams = {\n ...this.defaultOptions,\n ...options,\n // Unset options that should not be sent to the API\n __loadingType: undefined,\n __fetchSource: undefined,\n __experimentalCrossBrowserUpdates: undefined,\n };\n\n const result = await this.apiClient.makeRequest({\n method: \"GET\",\n url: `/v1/users/${this.knock.userId}/feeds/${this.feedId}`,\n params: queryParams,\n });\n\n if (result.statusCode === \"error\" || !result.body) {\n setState((store) => store.setNetworkStatus(NetworkStatus.error));\n\n return {\n status: result.statusCode,\n data: result.error || result.body,\n };\n }\n\n const response = {\n entries: result.body.entries,\n meta: result.body.meta,\n page_info: result.body.page_info,\n };\n\n if (options.before) {\n const opts = { shouldSetPage: false, shouldAppend: true };\n setState((state) => state.setResult(response, opts));\n } else if (options.after) {\n const opts = { shouldSetPage: true, shouldAppend: true };\n setState((state) => state.setResult(response, opts));\n } else {\n setState((state) => state.setResult(response));\n }\n\n // Legacy `messages.new` event, should be removed in a future version\n this.broadcast(\"messages.new\", response);\n\n // Broadcast the appropriate event type depending on the fetch source\n const feedEventType: FeedEvent =\n options.__fetchSource === \"socket\"\n ? \"items.received.realtime\"\n : \"items.received.page\";\n\n const eventPayload = {\n items: response.entries as FeedItem[],\n metadata: response.meta as FeedMetadata,\n event: feedEventType,\n };\n\n this.broadcast(eventPayload.event, eventPayload);\n\n return { data: response, status: result.statusCode };\n }\n\n async fetchNextPage() {\n // Attempts to fetch the next page of results (if we have any)\n const { getState } = this.store;\n const { pageInfo } = getState();\n\n if (!pageInfo.after) {\n // Nothing more to fetch\n return;\n }\n\n this.fetch({\n after: pageInfo.after,\n __loadingType: NetworkStatus.fetchMore,\n });\n }\n\n private broadcast(\n eventName: FeedEvent,\n data: FeedResponse | FeedEventPayload,\n ) {\n this.broadcaster.emit(eventName, data);\n }\n\n // Invoked when a new real-time message comes in from the socket\n private async onNewMessageReceived({\n metadata,\n }: FeedMessagesReceivedPayload) {\n // Handle the new message coming in\n const { getState, setState } = this.store;\n const { items } = getState();\n const currentHead: FeedItem | undefined = items[0];\n // Optimistically set the badge counts\n setState((state) => state.setMetadata(metadata));\n // Fetch the items before the current head (if it exists)\n this.fetch({ before: currentHead?.__cursor, __fetchSource: \"socket\" });\n }\n\n private buildUserFeedId() {\n return `${this.feedId}:${this.knock.userId}`;\n }\n\n private optimisticallyPerformStatusUpdate(\n itemOrItems: FeedItemOrItems,\n type: Status,\n attrs: object,\n badgeCountAttr?: \"unread_count\" | \"unseen_count\",\n ) {\n const { getState, setState } = this.store;\n const itemIds = Array.isArray(itemOrItems)\n ? itemOrItems.map((item) => item.id)\n : [itemOrItems.id];\n\n if (badgeCountAttr) {\n const { metadata } = getState();\n\n // Tnis is a hack to determine the direction of whether we're\n // adding or removing from the badge count\n const direction = type.startsWith(\"un\")\n ? itemIds.length\n : -itemIds.length;\n\n setState((store) =>\n store.setMetadata({\n ...metadata,\n [badgeCountAttr]: Math.max(0, metadata[badgeCountAttr] + direction),\n }),\n );\n }\n\n // Update the items with the given attributes\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n private async makeStatusUpdate(itemOrItems: FeedItemOrItems, type: Status) {\n // Always treat items as a batch to use the corresponding batch endpoint\n const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];\n const itemIds = items.map((item) => item.id);\n\n const result = await this.apiClient.makeRequest({\n method: \"POST\",\n url: `/v1/messages/batch/${type}`,\n data: { message_ids: itemIds },\n });\n\n // Emit the event that these items had their statuses changed\n // Note: we do this after the update to ensure that the server event actually completed\n this.broadcaster.emit(`items:${type}`, { items });\n this.broadcastOverChannel(`items:${type}`, { items });\n\n return result;\n }\n\n private async makeBulkStatusUpdate(type: \"seen\" | \"read\" | \"archive\") {\n // The base scope for the call should take into account all of the options currently\n // set on the feed, as well as being scoped for the current user. We do this so that\n // we ONLY make changes to the messages that are currently in view on this feed, and not\n // all messages that exist.\n const options = {\n user_ids: [this.knock.userId],\n engagement_status:\n this.defaultOptions.status !== \"all\"\n ? this.defaultOptions.status\n : undefined,\n archived: this.defaultOptions.archived,\n has_tenant: this.defaultOptions.has_tenant,\n tenants: this.defaultOptions.tenant\n ? [this.defaultOptions.tenant]\n : undefined,\n };\n\n return await this.apiClient.makeRequest({\n method: \"POST\",\n url: `/v1/channels/${this.feedId}/messages/bulk/${type}`,\n data: options,\n });\n }\n\n private broadcastOverChannel(type: string, payload: any) {\n // The broadcastChannel may not be available in non-browser environments\n if (!this.broadcastChannel) {\n return;\n }\n\n // Here we stringify our payload and try and send as JSON such that we\n // don't get any `An object could not be cloned` errors when trying to broadcast\n try {\n const stringifiedPayload = JSON.parse(JSON.stringify(payload));\n\n this.broadcastChannel.postMessage({\n type,\n payload: stringifiedPayload,\n });\n } catch (e) {\n console.warn(`Could not broadcast ${type}, got error: ${e}`);\n }\n }\n}\n\nexport default Feed;\n"],"file":"feed.js"}
1
+ {"version":3,"sources":["../../../../src/clients/feed/feed.ts"],"names":["feedClientDefaults","archived","Feed","knock","feedId","options","apiClient","client","userFeedId","buildUserFeedId","store","broadcaster","EventEmitter","wildcard","delimiter","defaultOptions","channel","socket","on","resp","onNewMessageReceived","broadcastChannel","self","BroadcastChannel","leave","removeAllListeners","off","destroy","close","isConnected","connect","includes","state","join","__experimentalCrossBrowserUpdates","onmessage","e","data","type","fetch","eventName","callback","getState","itemOrItems","now","Date","toISOString","optimisticallyPerformStatusUpdate","seen_at","makeStatusUpdate","setState","metadata","items","isViewingOnlyUnseen","status","resetStore","total_count","unseen_count","setMetadata","attrs","itemIds","map","item","id","setItemAttrs","makeBulkStatusUpdate","result","emit","broadcastOverChannel","read_at","isViewingOnlyUnread","unread_count","interacted_at","shouldOptimisticallyRemoveItems","normalizedItems","Array","isArray","unseenCount","filter","i","length","unreadCount","updatedMetadata","entriesToSet","setResult","entries","meta","page_info","pageInfo","archived_at","networkStatus","setNetworkStatus","__loadingType","NetworkStatus","loading","queryParams","undefined","__fetchSource","makeRequest","method","url","userId","params","statusCode","body","error","response","before","opts","shouldSetPage","shouldAppend","after","broadcast","feedEventType","eventPayload","event","fetchMore","currentHead","__cursor","badgeCountAttr","direction","startsWith","Math","max","message_ids","user_ids","engagement_status","has_tenant","tenants","tenant","payload","stringifiedPayload","JSON","parse","stringify","postMessage","console","warn"],"mappings":"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","sourcesContent":["import { Channel } from \"phoenix\";\nimport { StoreApi } from \"zustand\";\nimport { EventEmitter2 as EventEmitter } from \"eventemitter2\";\nimport ApiClient from \"../../api\";\nimport createStore from \"./store\";\nimport {\n BindableFeedEvent,\n FeedMessagesReceivedPayload,\n FeedEventCallback,\n FeedEvent,\n FeedItemOrItems,\n FeedStoreState,\n FeedEventPayload,\n FeedRealTimeCallback,\n} from \"./types\";\nimport {\n FeedItem,\n FeedClientOptions,\n FetchFeedOptions,\n FeedResponse,\n FeedMetadata,\n} from \"./interfaces\";\nimport Knock from \"../../knock\";\nimport { isRequestInFlight, NetworkStatus } from \"../../networkStatus\";\n\nexport type Status =\n | \"seen\"\n | \"read\"\n | \"interacted\"\n | \"archived\"\n | \"unseen\"\n | \"unread\"\n | \"unarchived\";\n\n// Default options to apply\nconst feedClientDefaults: Pick<FeedClientOptions, \"archived\"> = {\n archived: \"exclude\",\n};\n\nclass Feed {\n private apiClient: ApiClient;\n private userFeedId: string;\n private channel: Channel;\n private broadcaster: EventEmitter;\n private defaultOptions: FeedClientOptions;\n private broadcastChannel: BroadcastChannel | null;\n\n // The raw store instance, used for binding in React and other environments\n public store: StoreApi<FeedStoreState>;\n\n constructor(\n readonly knock: Knock,\n readonly feedId: string,\n options: FeedClientOptions,\n ) {\n this.apiClient = knock.client();\n this.feedId = feedId;\n this.userFeedId = this.buildUserFeedId();\n this.store = createStore();\n this.broadcaster = new EventEmitter({ wildcard: true, delimiter: \".\" });\n this.defaultOptions = { ...feedClientDefaults, ...options };\n\n this.channel = this.apiClient.socket.channel(\n `feeds:${this.userFeedId}`,\n this.defaultOptions,\n );\n\n this.channel.on(\"new-message\", (resp) => this.onNewMessageReceived(resp));\n\n // Attempt to bind to listen to other events from this feed in different tabs\n // Note: here we ensure `self` is available (it's not in server rendered envs)\n this.broadcastChannel =\n self && \"BroadcastChannel\" in self\n ? new BroadcastChannel(`knock:feed:${this.userFeedId}`)\n : null;\n }\n\n /**\n * Cleans up a feed instance by destroying the store and disconnecting\n * an open socket connection.\n */\n teardown() {\n this.channel.leave();\n this.broadcaster.removeAllListeners();\n this.channel.off(\"new-message\");\n this.store.destroy();\n\n if (this.broadcastChannel) {\n this.broadcastChannel.close();\n }\n }\n\n /*\n Initializes a real-time connection to Knock, connecting the websocket for the\n current ApiClient instance if the socket is not already connected.\n */\n listenForUpdates() {\n // Connect the socket only if we don't already have a connection\n if (!this.apiClient.socket.isConnected()) {\n this.apiClient.socket.connect();\n }\n\n // Only join the channel if we're not already in a joining state\n if ([\"closed\", \"errored\"].includes(this.channel.state)) {\n this.channel.join();\n }\n\n // Opt into receiving updates from _other tabs for the same user / feed_ via the broadcast\n // channel (iff it's enabled and exists)\n if (\n this.broadcastChannel &&\n this.defaultOptions.__experimentalCrossBrowserUpdates === true\n ) {\n this.broadcastChannel.onmessage = (e) => {\n switch (e.data.type) {\n case \"items:archived\":\n case \"items:unarchived\":\n case \"items:seen\":\n case \"items:unseen\":\n case \"items:read\":\n case \"items:unread\":\n case \"items:all_read\":\n case \"items:all_seen\":\n case \"items:all_archived\":\n // When items are updated in any other tab, simply refetch to get the latest state\n // to make sure that the state gets updated accordingly. In the future here we could\n // maybe do this optimistically without the fetch.\n return this.fetch();\n break;\n default:\n return null;\n }\n };\n }\n }\n\n /* Binds a handler to be invoked when event occurs */\n on(\n eventName: BindableFeedEvent,\n callback: FeedEventCallback | FeedRealTimeCallback,\n ) {\n this.broadcaster.on(eventName, callback);\n }\n\n off(\n eventName: BindableFeedEvent,\n callback: FeedEventCallback | FeedRealTimeCallback,\n ) {\n this.broadcaster.off(eventName, callback);\n }\n\n getState() {\n return this.store.getState();\n }\n\n async markAsSeen(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"seen\",\n { seen_at: now },\n \"unseen_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"seen\");\n }\n\n async markAllAsSeen() {\n // To mark all of the messages as seen we:\n // 1. Optimistically update *everything* we have in the store\n // 2. We decrement the `unseen_count` to zero optimistically\n // 3. We issue the API call to the endpoint\n //\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unseen_count` to be what it was.\n //\n // Note: here we optimistically handle the case whereby the feed is scoped to show only `unseen`\n // items by removing everything from view.\n const { getState, setState } = this.store;\n const { metadata, items } = getState();\n\n const isViewingOnlyUnseen = this.defaultOptions.status === \"unseen\";\n\n // If we're looking at the unseen view, then we want to remove all of the items optimistically\n // from the store given that nothing should be visible. We do this by resetting the store state\n // and setting the current metadata counts to 0\n if (isViewingOnlyUnseen) {\n setState((store) =>\n store.resetStore({\n ...metadata,\n total_count: 0,\n unseen_count: 0,\n }),\n );\n } else {\n // Otherwise we want to update the metadata and mark all of the items in the store as seen\n setState((store) => store.setMetadata({ ...metadata, unseen_count: 0 }));\n\n const attrs = { seen_at: new Date().toISOString() };\n const itemIds = items.map((item) => item.id);\n\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"seen\");\n\n this.broadcaster.emit(`items:all_seen`, { items });\n this.broadcastOverChannel(`items:all_seen`, { items });\n\n return result;\n }\n\n async markAsUnseen(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"unseen\",\n { seen_at: null },\n \"unseen_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"unseen\");\n }\n\n async markAsRead(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"read\",\n { read_at: now },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"read\");\n }\n\n async markAllAsRead() {\n // To mark all of the messages as read we:\n // 1. Optimistically update *everything* we have in the store\n // 2. We decrement the `unread_count` to zero optimistically\n // 3. We issue the API call to the endpoint\n //\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unread_count` to be what it was.\n //\n // Note: here we optimistically handle the case whereby the feed is scoped to show only `unread`\n // items by removing everything from view.\n const { getState, setState } = this.store;\n const { metadata, items } = getState();\n\n const isViewingOnlyUnread = this.defaultOptions.status === \"unread\";\n\n // If we're looking at the unread view, then we want to remove all of the items optimistically\n // from the store given that nothing should be visible. We do this by resetting the store state\n // and setting the current metadata counts to 0\n if (isViewingOnlyUnread) {\n setState((store) =>\n store.resetStore({\n ...metadata,\n total_count: 0,\n unread_count: 0,\n }),\n );\n } else {\n // Otherwise we want to update the metadata and mark all of the items in the store as seen\n setState((store) => store.setMetadata({ ...metadata, unread_count: 0 }));\n\n const attrs = { read_at: new Date().toISOString() };\n const itemIds = items.map((item) => item.id);\n\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"read\");\n\n this.broadcaster.emit(`items:all_read`, { items });\n this.broadcastOverChannel(`items:all_read`, { items });\n\n return result;\n }\n\n async markAsUnread(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"unread\",\n { read_at: null },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"unread\");\n }\n\n async markAsInteracted(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"interacted\",\n {\n read_at: now,\n interacted_at: now,\n },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"interacted\");\n }\n\n /*\n Marking one or more items as archived should:\n\n - Decrement the badge count for any unread / unseen items\n - Remove the item from the feed list when the `archived` flag is \"exclude\" (default)\n\n TODO: how do we handle rollbacks?\n */\n async markAsArchived(itemOrItems: FeedItemOrItems) {\n const { getState, setState } = this.store;\n const state = getState();\n\n const shouldOptimisticallyRemoveItems =\n this.defaultOptions.archived === \"exclude\";\n\n const normalizedItems = Array.isArray(itemOrItems)\n ? itemOrItems\n : [itemOrItems];\n\n const itemIds: string[] = normalizedItems.map((item) => item.id);\n\n /*\n In the code here we want to optimistically update counts and items\n that are persisted such that we can display updates immediately on the feed\n without needing to make a network request.\n\n Note: right now this does *not* take into account offline handling or any extensive retry\n logic, so rollbacks aren't considered. That probably needs to be a future consideration for\n this library.\n\n Scenarios to consider:\n\n ## Feed scope to archived *only*\n\n - Counts should not be decremented\n - Items should not be removed\n\n ## Feed scoped to exclude archived items (the default)\n\n - Counts should be decremented\n - Items should be removed\n\n ## Feed scoped to include archived items as well\n\n - Counts should not be decremented\n - Items should not be removed\n */\n\n if (shouldOptimisticallyRemoveItems) {\n // If any of the items are unseen or unread, then capture as we'll want to decrement\n // the counts for these in the metadata we have\n const unseenCount = normalizedItems.filter((i) => !i.seen_at).length;\n const unreadCount = normalizedItems.filter((i) => !i.read_at).length;\n\n // Build the new metadata\n const updatedMetadata = {\n ...state.metadata,\n total_count: state.metadata.total_count - normalizedItems.length,\n unseen_count: state.metadata.unseen_count - unseenCount,\n unread_count: state.metadata.unread_count - unreadCount,\n };\n\n // Remove the archiving entries\n const entriesToSet = state.items.filter(\n (item) => !itemIds.includes(item.id),\n );\n\n setState((state) =>\n state.setResult({\n entries: entriesToSet,\n meta: updatedMetadata,\n page_info: state.pageInfo,\n }),\n );\n } else {\n // Mark all the entries being updated as archived either way so the state is correct\n state.setItemAttrs(itemIds, { archived_at: new Date().toISOString() });\n }\n\n return this.makeStatusUpdate(itemOrItems, \"archived\");\n }\n\n async markAllAsArchived() {\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unseen_count` to be what it was.\n const { setState, getState } = this.store;\n const { items } = getState();\n\n // Here if we're looking at a feed that excludes all of the archived items by default then we\n // will want to optimistically remove all of the items from the feed as they are now all excluded\n const shouldOptimisticallyRemoveItems =\n this.defaultOptions.archived === \"exclude\";\n\n if (shouldOptimisticallyRemoveItems) {\n // Reset the store to clear out all of items and reset the badge count\n setState((store) => store.resetStore());\n } else {\n // Mark all the entries being updated as archived either way so the state is correct\n setState((store) => {\n const itemIds = items.map((i) => i.id);\n store.setItemAttrs(itemIds, { archived_at: new Date().toISOString() });\n });\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"archive\");\n\n this.broadcaster.emit(`items:all_archived`, { items });\n this.broadcastOverChannel(`items:all_archived`, { items });\n\n return result;\n }\n\n async markAsUnarchived(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(itemOrItems, \"unarchived\", {\n archived_at: null,\n });\n\n return this.makeStatusUpdate(itemOrItems, \"unarchived\");\n }\n\n /* Fetches the feed content, appending it to the store */\n async fetch(options: FetchFeedOptions = {}) {\n const { setState, getState } = this.store;\n const { networkStatus } = getState();\n\n // If there's an existing request in flight, then do nothing\n if (isRequestInFlight(networkStatus)) {\n return;\n }\n\n // Set the loading type based on the request type it is\n setState((store) =>\n store.setNetworkStatus(options.__loadingType ?? NetworkStatus.loading),\n );\n\n // Always include the default params, if they have been set\n const queryParams = {\n ...this.defaultOptions,\n ...options,\n // Unset options that should not be sent to the API\n __loadingType: undefined,\n __fetchSource: undefined,\n __experimentalCrossBrowserUpdates: undefined,\n };\n\n const result = await this.apiClient.makeRequest({\n method: \"GET\",\n url: `/v1/users/${this.knock.userId}/feeds/${this.feedId}`,\n params: queryParams,\n });\n\n if (result.statusCode === \"error\" || !result.body) {\n setState((store) => store.setNetworkStatus(NetworkStatus.error));\n\n return {\n status: result.statusCode,\n data: result.error || result.body,\n };\n }\n\n const response = {\n entries: result.body.entries,\n meta: result.body.meta,\n page_info: result.body.page_info,\n };\n\n if (options.before) {\n const opts = { shouldSetPage: false, shouldAppend: true };\n setState((state) => state.setResult(response, opts));\n } else if (options.after) {\n const opts = { shouldSetPage: true, shouldAppend: true };\n setState((state) => state.setResult(response, opts));\n } else {\n setState((state) => state.setResult(response));\n }\n\n // Legacy `messages.new` event, should be removed in a future version\n this.broadcast(\"messages.new\", response);\n\n // Broadcast the appropriate event type depending on the fetch source\n const feedEventType: FeedEvent =\n options.__fetchSource === \"socket\"\n ? \"items.received.realtime\"\n : \"items.received.page\";\n\n const eventPayload = {\n items: response.entries as FeedItem[],\n metadata: response.meta as FeedMetadata,\n event: feedEventType,\n };\n\n this.broadcast(eventPayload.event, eventPayload);\n\n return { data: response, status: result.statusCode };\n }\n\n async fetchNextPage() {\n // Attempts to fetch the next page of results (if we have any)\n const { getState } = this.store;\n const { pageInfo } = getState();\n\n if (!pageInfo.after) {\n // Nothing more to fetch\n return;\n }\n\n this.fetch({\n after: pageInfo.after,\n __loadingType: NetworkStatus.fetchMore,\n });\n }\n\n private broadcast(\n eventName: FeedEvent,\n data: FeedResponse | FeedEventPayload,\n ) {\n this.broadcaster.emit(eventName, data);\n }\n\n // Invoked when a new real-time message comes in from the socket\n private async onNewMessageReceived({\n metadata,\n }: FeedMessagesReceivedPayload) {\n // Handle the new message coming in\n const { getState, setState } = this.store;\n const { items } = getState();\n const currentHead: FeedItem | undefined = items[0];\n // Optimistically set the badge counts\n setState((state) => state.setMetadata(metadata));\n // Fetch the items before the current head (if it exists)\n this.fetch({ before: currentHead?.__cursor, __fetchSource: \"socket\" });\n }\n\n private buildUserFeedId() {\n return `${this.feedId}:${this.knock.userId}`;\n }\n\n private optimisticallyPerformStatusUpdate(\n itemOrItems: FeedItemOrItems,\n type: Status,\n attrs: object,\n badgeCountAttr?: \"unread_count\" | \"unseen_count\",\n ) {\n const { getState, setState } = this.store;\n const itemIds = Array.isArray(itemOrItems)\n ? itemOrItems.map((item) => item.id)\n : [itemOrItems.id];\n\n if (badgeCountAttr) {\n const { metadata } = getState();\n\n // Tnis is a hack to determine the direction of whether we're\n // adding or removing from the badge count\n const direction = type.startsWith(\"un\")\n ? itemIds.length\n : -itemIds.length;\n\n setState((store) =>\n store.setMetadata({\n ...metadata,\n [badgeCountAttr]: Math.max(0, metadata[badgeCountAttr] + direction),\n }),\n );\n }\n\n // Update the items with the given attributes\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n private async makeStatusUpdate(itemOrItems: FeedItemOrItems, type: Status) {\n // Always treat items as a batch to use the corresponding batch endpoint\n const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];\n const itemIds = items.map((item) => item.id);\n\n const result = await this.apiClient.makeRequest({\n method: \"POST\",\n url: `/v1/messages/batch/${type}`,\n data: { message_ids: itemIds },\n });\n\n // Emit the event that these items had their statuses changed\n // Note: we do this after the update to ensure that the server event actually completed\n this.broadcaster.emit(`items:${type}`, { items });\n this.broadcastOverChannel(`items:${type}`, { items });\n\n return result;\n }\n\n private async makeBulkStatusUpdate(type: \"seen\" | \"read\" | \"archive\") {\n // The base scope for the call should take into account all of the options currently\n // set on the feed, as well as being scoped for the current user. We do this so that\n // we ONLY make changes to the messages that are currently in view on this feed, and not\n // all messages that exist.\n const options = {\n user_ids: [this.knock.userId],\n engagement_status:\n this.defaultOptions.status !== \"all\"\n ? this.defaultOptions.status\n : undefined,\n archived: this.defaultOptions.archived,\n has_tenant: this.defaultOptions.has_tenant,\n tenants: this.defaultOptions.tenant\n ? [this.defaultOptions.tenant]\n : undefined,\n };\n\n return await this.apiClient.makeRequest({\n method: \"POST\",\n url: `/v1/channels/${this.feedId}/messages/bulk/${type}`,\n data: options,\n });\n }\n\n private broadcastOverChannel(type: string, payload: any) {\n // The broadcastChannel may not be available in non-browser environments\n if (!this.broadcastChannel) {\n return;\n }\n\n // Here we stringify our payload and try and send as JSON such that we\n // don't get any `An object could not be cloned` errors when trying to broadcast\n try {\n const stringifiedPayload = JSON.parse(JSON.stringify(payload));\n\n this.broadcastChannel.postMessage({\n type,\n payload: stringifiedPayload,\n });\n } catch (e) {\n console.warn(`Could not broadcast ${type}, got error: ${e}`);\n }\n }\n}\n\nexport default Feed;\n"],"file":"feed.js"}
@@ -291,6 +291,21 @@ class Feed {
291
291
  return _this6.makeStatusUpdate(itemOrItems, "unread");
292
292
  })();
293
293
  }
294
+
295
+ markAsInteracted(itemOrItems) {
296
+ var _this7 = this;
297
+
298
+ return _asyncToGenerator(function* () {
299
+ var now = new Date().toISOString();
300
+
301
+ _this7.optimisticallyPerformStatusUpdate(itemOrItems, "interacted", {
302
+ read_at: now,
303
+ interacted_at: now
304
+ }, "unread_count");
305
+
306
+ return _this7.makeStatusUpdate(itemOrItems, "interacted");
307
+ })();
308
+ }
294
309
  /*
295
310
  Marking one or more items as archived should:
296
311
  - Decrement the badge count for any unread / unseen items
@@ -300,15 +315,15 @@ class Feed {
300
315
 
301
316
 
302
317
  markAsArchived(itemOrItems) {
303
- var _this7 = this;
318
+ var _this8 = this;
304
319
 
305
320
  return _asyncToGenerator(function* () {
306
321
  var {
307
322
  getState,
308
323
  setState
309
- } = _this7.store;
324
+ } = _this8.store;
310
325
  var state = getState();
311
- var shouldOptimisticallyRemoveItems = _this7.defaultOptions.archived === "exclude";
326
+ var shouldOptimisticallyRemoveItems = _this8.defaultOptions.archived === "exclude";
312
327
  var normalizedItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
313
328
  var itemIds = normalizedItems.map(item => item.id);
314
329
  /*
@@ -356,12 +371,12 @@ class Feed {
356
371
  });
357
372
  }
358
373
 
359
- return _this7.makeStatusUpdate(itemOrItems, "archived");
374
+ return _this8.makeStatusUpdate(itemOrItems, "archived");
360
375
  })();
361
376
  }
362
377
 
363
378
  markAllAsArchived() {
364
- var _this8 = this;
379
+ var _this9 = this;
365
380
 
366
381
  return _asyncToGenerator(function* () {
367
382
  // Note: there is the potential for a race condition here because the bulk
@@ -370,13 +385,13 @@ class Feed {
370
385
  var {
371
386
  setState,
372
387
  getState
373
- } = _this8.store;
388
+ } = _this9.store;
374
389
  var {
375
390
  items
376
391
  } = getState(); // Here if we're looking at a feed that excludes all of the archived items by default then we
377
392
  // will want to optimistically remove all of the items from the feed as they are now all excluded
378
393
 
379
- var shouldOptimisticallyRemoveItems = _this8.defaultOptions.archived === "exclude";
394
+ var shouldOptimisticallyRemoveItems = _this9.defaultOptions.archived === "exclude";
380
395
 
381
396
  if (shouldOptimisticallyRemoveItems) {
382
397
  // Reset the store to clear out all of items and reset the badge count
@@ -392,13 +407,13 @@ class Feed {
392
407
  } // Issue the API request to the bulk status change API
393
408
 
394
409
 
395
- var result = yield _this8.makeBulkStatusUpdate("archive");
410
+ var result = yield _this9.makeBulkStatusUpdate("archive");
396
411
 
397
- _this8.broadcaster.emit("items:all_archived", {
412
+ _this9.broadcaster.emit("items:all_archived", {
398
413
  items
399
414
  });
400
415
 
401
- _this8.broadcastOverChannel("items:all_archived", {
416
+ _this9.broadcastOverChannel("items:all_archived", {
402
417
  items
403
418
  });
404
419
 
@@ -407,14 +422,14 @@ class Feed {
407
422
  }
408
423
 
409
424
  markAsUnarchived(itemOrItems) {
410
- var _this9 = this;
425
+ var _this10 = this;
411
426
 
412
427
  return _asyncToGenerator(function* () {
413
- _this9.optimisticallyPerformStatusUpdate(itemOrItems, "unarchived", {
428
+ _this10.optimisticallyPerformStatusUpdate(itemOrItems, "unarchived", {
414
429
  archived_at: null
415
430
  });
416
431
 
417
- return _this9.makeStatusUpdate(itemOrItems, "unarchived");
432
+ return _this10.makeStatusUpdate(itemOrItems, "unarchived");
418
433
  })();
419
434
  }
420
435
  /* Fetches the feed content, appending it to the store */
@@ -422,14 +437,14 @@ class Feed {
422
437
 
423
438
  fetch() {
424
439
  var _arguments = arguments,
425
- _this10 = this;
440
+ _this11 = this;
426
441
 
427
442
  return _asyncToGenerator(function* () {
428
443
  var options = _arguments.length > 0 && _arguments[0] !== undefined ? _arguments[0] : {};
429
444
  var {
430
445
  setState,
431
446
  getState
432
- } = _this10.store;
447
+ } = _this11.store;
433
448
  var {
434
449
  networkStatus
435
450
  } = getState(); // If there's an existing request in flight, then do nothing
@@ -445,16 +460,16 @@ class Feed {
445
460
  return store.setNetworkStatus((_options$__loadingTyp = options.__loadingType) !== null && _options$__loadingTyp !== void 0 ? _options$__loadingTyp : NetworkStatus.loading);
446
461
  }); // Always include the default params, if they have been set
447
462
 
448
- var queryParams = _objectSpread(_objectSpread(_objectSpread({}, _this10.defaultOptions), options), {}, {
463
+ var queryParams = _objectSpread(_objectSpread(_objectSpread({}, _this11.defaultOptions), options), {}, {
449
464
  // Unset options that should not be sent to the API
450
465
  __loadingType: undefined,
451
466
  __fetchSource: undefined,
452
467
  __experimentalCrossBrowserUpdates: undefined
453
468
  });
454
469
 
455
- var result = yield _this10.apiClient.makeRequest({
470
+ var result = yield _this11.apiClient.makeRequest({
456
471
  method: "GET",
457
- url: "/v1/users/".concat(_this10.knock.userId, "/feeds/").concat(_this10.feedId),
472
+ url: "/v1/users/".concat(_this11.knock.userId, "/feeds/").concat(_this11.feedId),
458
473
  params: queryParams
459
474
  });
460
475
 
@@ -489,7 +504,7 @@ class Feed {
489
504
  } // Legacy `messages.new` event, should be removed in a future version
490
505
 
491
506
 
492
- _this10.broadcast("messages.new", response); // Broadcast the appropriate event type depending on the fetch source
507
+ _this11.broadcast("messages.new", response); // Broadcast the appropriate event type depending on the fetch source
493
508
 
494
509
 
495
510
  var feedEventType = options.__fetchSource === "socket" ? "items.received.realtime" : "items.received.page";
@@ -499,7 +514,7 @@ class Feed {
499
514
  event: feedEventType
500
515
  };
501
516
 
502
- _this10.broadcast(eventPayload.event, eventPayload);
517
+ _this11.broadcast(eventPayload.event, eventPayload);
503
518
 
504
519
  return {
505
520
  data: response,
@@ -509,13 +524,13 @@ class Feed {
509
524
  }
510
525
 
511
526
  fetchNextPage() {
512
- var _this11 = this;
527
+ var _this12 = this;
513
528
 
514
529
  return _asyncToGenerator(function* () {
515
530
  // Attempts to fetch the next page of results (if we have any)
516
531
  var {
517
532
  getState
518
- } = _this11.store;
533
+ } = _this12.store;
519
534
  var {
520
535
  pageInfo
521
536
  } = getState();
@@ -525,7 +540,7 @@ class Feed {
525
540
  return;
526
541
  }
527
542
 
528
- _this11.fetch({
543
+ _this12.fetch({
529
544
  after: pageInfo.after,
530
545
  __loadingType: NetworkStatus.fetchMore
531
546
  });
@@ -538,7 +553,7 @@ class Feed {
538
553
 
539
554
 
540
555
  onNewMessageReceived(_ref) {
541
- var _this12 = this;
556
+ var _this13 = this;
542
557
 
543
558
  return _asyncToGenerator(function* () {
544
559
  var {
@@ -548,7 +563,7 @@ class Feed {
548
563
  var {
549
564
  getState,
550
565
  setState
551
- } = _this12.store;
566
+ } = _this13.store;
552
567
  var {
553
568
  items
554
569
  } = getState();
@@ -556,7 +571,7 @@ class Feed {
556
571
 
557
572
  setState(state => state.setMetadata(metadata)); // Fetch the items before the current head (if it exists)
558
573
 
559
- _this12.fetch({
574
+ _this13.fetch({
560
575
  before: currentHead === null || currentHead === void 0 ? void 0 : currentHead.__cursor,
561
576
  __fetchSource: "socket"
562
577
  });
@@ -591,13 +606,13 @@ class Feed {
591
606
  }
592
607
 
593
608
  makeStatusUpdate(itemOrItems, type) {
594
- var _this13 = this;
609
+ var _this14 = this;
595
610
 
596
611
  return _asyncToGenerator(function* () {
597
612
  // Always treat items as a batch to use the corresponding batch endpoint
598
613
  var items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
599
614
  var itemIds = items.map(item => item.id);
600
- var result = yield _this13.apiClient.makeRequest({
615
+ var result = yield _this14.apiClient.makeRequest({
601
616
  method: "POST",
602
617
  url: "/v1/messages/batch/".concat(type),
603
618
  data: {
@@ -606,11 +621,11 @@ class Feed {
606
621
  }); // Emit the event that these items had their statuses changed
607
622
  // Note: we do this after the update to ensure that the server event actually completed
608
623
 
609
- _this13.broadcaster.emit("items:".concat(type), {
624
+ _this14.broadcaster.emit("items:".concat(type), {
610
625
  items
611
626
  });
612
627
 
613
- _this13.broadcastOverChannel("items:".concat(type), {
628
+ _this14.broadcastOverChannel("items:".concat(type), {
614
629
  items
615
630
  });
616
631
 
@@ -619,7 +634,7 @@ class Feed {
619
634
  }
620
635
 
621
636
  makeBulkStatusUpdate(type) {
622
- var _this14 = this;
637
+ var _this15 = this;
623
638
 
624
639
  return _asyncToGenerator(function* () {
625
640
  // The base scope for the call should take into account all of the options currently
@@ -627,15 +642,15 @@ class Feed {
627
642
  // we ONLY make changes to the messages that are currently in view on this feed, and not
628
643
  // all messages that exist.
629
644
  var options = {
630
- user_ids: [_this14.knock.userId],
631
- engagement_status: _this14.defaultOptions.status !== "all" ? _this14.defaultOptions.status : undefined,
632
- archived: _this14.defaultOptions.archived,
633
- has_tenant: _this14.defaultOptions.has_tenant,
634
- tenants: _this14.defaultOptions.tenant ? [_this14.defaultOptions.tenant] : undefined
645
+ user_ids: [_this15.knock.userId],
646
+ engagement_status: _this15.defaultOptions.status !== "all" ? _this15.defaultOptions.status : undefined,
647
+ archived: _this15.defaultOptions.archived,
648
+ has_tenant: _this15.defaultOptions.has_tenant,
649
+ tenants: _this15.defaultOptions.tenant ? [_this15.defaultOptions.tenant] : undefined
635
650
  };
636
- return yield _this14.apiClient.makeRequest({
651
+ return yield _this15.apiClient.makeRequest({
637
652
  method: "POST",
638
- url: "/v1/channels/".concat(_this14.feedId, "/messages/bulk/").concat(type),
653
+ url: "/v1/channels/".concat(_this15.feedId, "/messages/bulk/").concat(type),
639
654
  data: options
640
655
  });
641
656
  })();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/clients/feed/feed.ts"],"names":["EventEmitter2","EventEmitter","createStore","isRequestInFlight","NetworkStatus","feedClientDefaults","archived","Feed","constructor","knock","feedId","options","apiClient","client","userFeedId","buildUserFeedId","store","broadcaster","wildcard","delimiter","defaultOptions","channel","socket","on","resp","onNewMessageReceived","broadcastChannel","self","BroadcastChannel","teardown","leave","removeAllListeners","off","destroy","close","listenForUpdates","isConnected","connect","includes","state","join","__experimentalCrossBrowserUpdates","onmessage","e","data","type","fetch","eventName","callback","getState","markAsSeen","itemOrItems","now","Date","toISOString","optimisticallyPerformStatusUpdate","seen_at","makeStatusUpdate","markAllAsSeen","setState","metadata","items","isViewingOnlyUnseen","status","resetStore","total_count","unseen_count","setMetadata","attrs","itemIds","map","item","id","setItemAttrs","result","makeBulkStatusUpdate","emit","broadcastOverChannel","markAsUnseen","markAsRead","read_at","markAllAsRead","isViewingOnlyUnread","unread_count","markAsUnread","markAsArchived","shouldOptimisticallyRemoveItems","normalizedItems","Array","isArray","unseenCount","filter","i","length","unreadCount","updatedMetadata","entriesToSet","setResult","entries","meta","page_info","pageInfo","archived_at","markAllAsArchived","markAsUnarchived","networkStatus","setNetworkStatus","__loadingType","loading","queryParams","undefined","__fetchSource","makeRequest","method","url","userId","params","statusCode","body","error","response","before","opts","shouldSetPage","shouldAppend","after","broadcast","feedEventType","eventPayload","event","fetchNextPage","fetchMore","currentHead","__cursor","badgeCountAttr","direction","startsWith","Math","max","message_ids","user_ids","engagement_status","has_tenant","tenants","tenant","payload","stringifiedPayload","JSON","parse","stringify","postMessage","console","warn"],"mappings":"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","sourcesContent":["import { Channel } from \"phoenix\";\nimport { StoreApi } from \"zustand\";\nimport { EventEmitter2 as EventEmitter } from \"eventemitter2\";\nimport ApiClient from \"../../api\";\nimport createStore from \"./store\";\nimport {\n BindableFeedEvent,\n FeedMessagesReceivedPayload,\n FeedEventCallback,\n FeedEvent,\n FeedItemOrItems,\n FeedStoreState,\n FeedEventPayload,\n FeedRealTimeCallback,\n} from \"./types\";\nimport {\n FeedItem,\n FeedClientOptions,\n FetchFeedOptions,\n FeedResponse,\n FeedMetadata,\n} from \"./interfaces\";\nimport Knock from \"../../knock\";\nimport { isRequestInFlight, NetworkStatus } from \"../../networkStatus\";\n\nexport type Status =\n | \"seen\"\n | \"read\"\n | \"archived\"\n | \"unseen\"\n | \"unread\"\n | \"unarchived\";\n\n// Default options to apply\nconst feedClientDefaults: Pick<FeedClientOptions, \"archived\"> = {\n archived: \"exclude\",\n};\n\nclass Feed {\n private apiClient: ApiClient;\n private userFeedId: string;\n private channel: Channel;\n private broadcaster: EventEmitter;\n private defaultOptions: FeedClientOptions;\n private broadcastChannel: BroadcastChannel | null;\n\n // The raw store instance, used for binding in React and other environments\n public store: StoreApi<FeedStoreState>;\n\n constructor(\n readonly knock: Knock,\n readonly feedId: string,\n options: FeedClientOptions,\n ) {\n this.apiClient = knock.client();\n this.feedId = feedId;\n this.userFeedId = this.buildUserFeedId();\n this.store = createStore();\n this.broadcaster = new EventEmitter({ wildcard: true, delimiter: \".\" });\n this.defaultOptions = { ...feedClientDefaults, ...options };\n\n this.channel = this.apiClient.socket.channel(\n `feeds:${this.userFeedId}`,\n this.defaultOptions,\n );\n\n this.channel.on(\"new-message\", (resp) => this.onNewMessageReceived(resp));\n\n // Attempt to bind to listen to other events from this feed in different tabs\n // Note: here we ensure `self` is available (it's not in server rendered envs)\n this.broadcastChannel =\n self && \"BroadcastChannel\" in self\n ? new BroadcastChannel(`knock:feed:${this.userFeedId}`)\n : null;\n }\n\n /**\n * Cleans up a feed instance by destroying the store and disconnecting\n * an open socket connection.\n */\n teardown() {\n this.channel.leave();\n this.broadcaster.removeAllListeners();\n this.channel.off(\"new-message\");\n this.store.destroy();\n\n if (this.broadcastChannel) {\n this.broadcastChannel.close();\n }\n }\n\n /*\n Initializes a real-time connection to Knock, connecting the websocket for the\n current ApiClient instance if the socket is not already connected.\n */\n listenForUpdates() {\n // Connect the socket only if we don't already have a connection\n if (!this.apiClient.socket.isConnected()) {\n this.apiClient.socket.connect();\n }\n\n // Only join the channel if we're not already in a joining state\n if ([\"closed\", \"errored\"].includes(this.channel.state)) {\n this.channel.join();\n }\n\n // Opt into receiving updates from _other tabs for the same user / feed_ via the broadcast\n // channel (iff it's enabled and exists)\n if (\n this.broadcastChannel &&\n this.defaultOptions.__experimentalCrossBrowserUpdates === true\n ) {\n this.broadcastChannel.onmessage = (e) => {\n switch (e.data.type) {\n case \"items:archived\":\n case \"items:unarchived\":\n case \"items:seen\":\n case \"items:unseen\":\n case \"items:read\":\n case \"items:unread\":\n case \"items:all_read\":\n case \"items:all_seen\":\n case \"items:all_archived\":\n // When items are updated in any other tab, simply refetch to get the latest state\n // to make sure that the state gets updated accordingly. In the future here we could\n // maybe do this optimistically without the fetch.\n return this.fetch();\n break;\n default:\n return null;\n }\n };\n }\n }\n\n /* Binds a handler to be invoked when event occurs */\n on(\n eventName: BindableFeedEvent,\n callback: FeedEventCallback | FeedRealTimeCallback,\n ) {\n this.broadcaster.on(eventName, callback);\n }\n\n off(\n eventName: BindableFeedEvent,\n callback: FeedEventCallback | FeedRealTimeCallback,\n ) {\n this.broadcaster.off(eventName, callback);\n }\n\n getState() {\n return this.store.getState();\n }\n\n async markAsSeen(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"seen\",\n { seen_at: now },\n \"unseen_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"seen\");\n }\n\n async markAllAsSeen() {\n // To mark all of the messages as seen we:\n // 1. Optimistically update *everything* we have in the store\n // 2. We decrement the `unseen_count` to zero optimistically\n // 3. We issue the API call to the endpoint\n //\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unseen_count` to be what it was.\n //\n // Note: here we optimistically handle the case whereby the feed is scoped to show only `unseen`\n // items by removing everything from view.\n const { getState, setState } = this.store;\n const { metadata, items } = getState();\n\n const isViewingOnlyUnseen = this.defaultOptions.status === \"unseen\";\n\n // If we're looking at the unseen view, then we want to remove all of the items optimistically\n // from the store given that nothing should be visible. We do this by resetting the store state\n // and setting the current metadata counts to 0\n if (isViewingOnlyUnseen) {\n setState((store) =>\n store.resetStore({\n ...metadata,\n total_count: 0,\n unseen_count: 0,\n }),\n );\n } else {\n // Otherwise we want to update the metadata and mark all of the items in the store as seen\n setState((store) => store.setMetadata({ ...metadata, unseen_count: 0 }));\n\n const attrs = { seen_at: new Date().toISOString() };\n const itemIds = items.map((item) => item.id);\n\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"seen\");\n\n this.broadcaster.emit(`items:all_seen`, { items });\n this.broadcastOverChannel(`items:all_seen`, { items });\n\n return result;\n }\n\n async markAsUnseen(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"unseen\",\n { seen_at: null },\n \"unseen_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"unseen\");\n }\n\n async markAsRead(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"read\",\n { read_at: now },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"read\");\n }\n\n async markAllAsRead() {\n // To mark all of the messages as read we:\n // 1. Optimistically update *everything* we have in the store\n // 2. We decrement the `unread_count` to zero optimistically\n // 3. We issue the API call to the endpoint\n //\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unread_count` to be what it was.\n //\n // Note: here we optimistically handle the case whereby the feed is scoped to show only `unread`\n // items by removing everything from view.\n const { getState, setState } = this.store;\n const { metadata, items } = getState();\n\n const isViewingOnlyUnread = this.defaultOptions.status === \"unread\";\n\n // If we're looking at the unread view, then we want to remove all of the items optimistically\n // from the store given that nothing should be visible. We do this by resetting the store state\n // and setting the current metadata counts to 0\n if (isViewingOnlyUnread) {\n setState((store) =>\n store.resetStore({\n ...metadata,\n total_count: 0,\n unread_count: 0,\n }),\n );\n } else {\n // Otherwise we want to update the metadata and mark all of the items in the store as seen\n setState((store) => store.setMetadata({ ...metadata, unread_count: 0 }));\n\n const attrs = { read_at: new Date().toISOString() };\n const itemIds = items.map((item) => item.id);\n\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"read\");\n\n this.broadcaster.emit(`items:all_read`, { items });\n this.broadcastOverChannel(`items:all_read`, { items });\n\n return result;\n }\n\n async markAsUnread(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"unread\",\n { read_at: null },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"unread\");\n }\n\n /*\n Marking one or more items as archived should:\n\n - Decrement the badge count for any unread / unseen items\n - Remove the item from the feed list when the `archived` flag is \"exclude\" (default)\n\n TODO: how do we handle rollbacks?\n */\n async markAsArchived(itemOrItems: FeedItemOrItems) {\n const { getState, setState } = this.store;\n const state = getState();\n\n const shouldOptimisticallyRemoveItems =\n this.defaultOptions.archived === \"exclude\";\n\n const normalizedItems = Array.isArray(itemOrItems)\n ? itemOrItems\n : [itemOrItems];\n\n const itemIds: string[] = normalizedItems.map((item) => item.id);\n\n /*\n In the code here we want to optimistically update counts and items\n that are persisted such that we can display updates immediately on the feed\n without needing to make a network request.\n\n Note: right now this does *not* take into account offline handling or any extensive retry\n logic, so rollbacks aren't considered. That probably needs to be a future consideration for\n this library.\n\n Scenarios to consider:\n\n ## Feed scope to archived *only*\n\n - Counts should not be decremented\n - Items should not be removed\n\n ## Feed scoped to exclude archived items (the default)\n\n - Counts should be decremented\n - Items should be removed\n\n ## Feed scoped to include archived items as well\n\n - Counts should not be decremented\n - Items should not be removed\n */\n\n if (shouldOptimisticallyRemoveItems) {\n // If any of the items are unseen or unread, then capture as we'll want to decrement\n // the counts for these in the metadata we have\n const unseenCount = normalizedItems.filter((i) => !i.seen_at).length;\n const unreadCount = normalizedItems.filter((i) => !i.read_at).length;\n\n // Build the new metadata\n const updatedMetadata = {\n ...state.metadata,\n total_count: state.metadata.total_count - normalizedItems.length,\n unseen_count: state.metadata.unseen_count - unseenCount,\n unread_count: state.metadata.unread_count - unreadCount,\n };\n\n // Remove the archiving entries\n const entriesToSet = state.items.filter(\n (item) => !itemIds.includes(item.id),\n );\n\n setState((state) =>\n state.setResult({\n entries: entriesToSet,\n meta: updatedMetadata,\n page_info: state.pageInfo,\n }),\n );\n } else {\n // Mark all the entries being updated as archived either way so the state is correct\n state.setItemAttrs(itemIds, { archived_at: new Date().toISOString() });\n }\n\n return this.makeStatusUpdate(itemOrItems, \"archived\");\n }\n\n async markAllAsArchived() {\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unseen_count` to be what it was.\n const { setState, getState } = this.store;\n const { items } = getState();\n\n // Here if we're looking at a feed that excludes all of the archived items by default then we\n // will want to optimistically remove all of the items from the feed as they are now all excluded\n const shouldOptimisticallyRemoveItems =\n this.defaultOptions.archived === \"exclude\";\n\n if (shouldOptimisticallyRemoveItems) {\n // Reset the store to clear out all of items and reset the badge count\n setState((store) => store.resetStore());\n } else {\n // Mark all the entries being updated as archived either way so the state is correct\n setState((store) => {\n const itemIds = items.map((i) => i.id);\n store.setItemAttrs(itemIds, { archived_at: new Date().toISOString() });\n });\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"archive\");\n\n this.broadcaster.emit(`items:all_archived`, { items });\n this.broadcastOverChannel(`items:all_archived`, { items });\n\n return result;\n }\n\n async markAsUnarchived(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(itemOrItems, \"unarchived\", {\n archived_at: null,\n });\n\n return this.makeStatusUpdate(itemOrItems, \"unarchived\");\n }\n\n /* Fetches the feed content, appending it to the store */\n async fetch(options: FetchFeedOptions = {}) {\n const { setState, getState } = this.store;\n const { networkStatus } = getState();\n\n // If there's an existing request in flight, then do nothing\n if (isRequestInFlight(networkStatus)) {\n return;\n }\n\n // Set the loading type based on the request type it is\n setState((store) =>\n store.setNetworkStatus(options.__loadingType ?? NetworkStatus.loading),\n );\n\n // Always include the default params, if they have been set\n const queryParams = {\n ...this.defaultOptions,\n ...options,\n // Unset options that should not be sent to the API\n __loadingType: undefined,\n __fetchSource: undefined,\n __experimentalCrossBrowserUpdates: undefined,\n };\n\n const result = await this.apiClient.makeRequest({\n method: \"GET\",\n url: `/v1/users/${this.knock.userId}/feeds/${this.feedId}`,\n params: queryParams,\n });\n\n if (result.statusCode === \"error\" || !result.body) {\n setState((store) => store.setNetworkStatus(NetworkStatus.error));\n\n return {\n status: result.statusCode,\n data: result.error || result.body,\n };\n }\n\n const response = {\n entries: result.body.entries,\n meta: result.body.meta,\n page_info: result.body.page_info,\n };\n\n if (options.before) {\n const opts = { shouldSetPage: false, shouldAppend: true };\n setState((state) => state.setResult(response, opts));\n } else if (options.after) {\n const opts = { shouldSetPage: true, shouldAppend: true };\n setState((state) => state.setResult(response, opts));\n } else {\n setState((state) => state.setResult(response));\n }\n\n // Legacy `messages.new` event, should be removed in a future version\n this.broadcast(\"messages.new\", response);\n\n // Broadcast the appropriate event type depending on the fetch source\n const feedEventType: FeedEvent =\n options.__fetchSource === \"socket\"\n ? \"items.received.realtime\"\n : \"items.received.page\";\n\n const eventPayload = {\n items: response.entries as FeedItem[],\n metadata: response.meta as FeedMetadata,\n event: feedEventType,\n };\n\n this.broadcast(eventPayload.event, eventPayload);\n\n return { data: response, status: result.statusCode };\n }\n\n async fetchNextPage() {\n // Attempts to fetch the next page of results (if we have any)\n const { getState } = this.store;\n const { pageInfo } = getState();\n\n if (!pageInfo.after) {\n // Nothing more to fetch\n return;\n }\n\n this.fetch({\n after: pageInfo.after,\n __loadingType: NetworkStatus.fetchMore,\n });\n }\n\n private broadcast(\n eventName: FeedEvent,\n data: FeedResponse | FeedEventPayload,\n ) {\n this.broadcaster.emit(eventName, data);\n }\n\n // Invoked when a new real-time message comes in from the socket\n private async onNewMessageReceived({\n metadata,\n }: FeedMessagesReceivedPayload) {\n // Handle the new message coming in\n const { getState, setState } = this.store;\n const { items } = getState();\n const currentHead: FeedItem | undefined = items[0];\n // Optimistically set the badge counts\n setState((state) => state.setMetadata(metadata));\n // Fetch the items before the current head (if it exists)\n this.fetch({ before: currentHead?.__cursor, __fetchSource: \"socket\" });\n }\n\n private buildUserFeedId() {\n return `${this.feedId}:${this.knock.userId}`;\n }\n\n private optimisticallyPerformStatusUpdate(\n itemOrItems: FeedItemOrItems,\n type: Status,\n attrs: object,\n badgeCountAttr?: \"unread_count\" | \"unseen_count\",\n ) {\n const { getState, setState } = this.store;\n const itemIds = Array.isArray(itemOrItems)\n ? itemOrItems.map((item) => item.id)\n : [itemOrItems.id];\n\n if (badgeCountAttr) {\n const { metadata } = getState();\n\n // Tnis is a hack to determine the direction of whether we're\n // adding or removing from the badge count\n const direction = type.startsWith(\"un\")\n ? itemIds.length\n : -itemIds.length;\n\n setState((store) =>\n store.setMetadata({\n ...metadata,\n [badgeCountAttr]: Math.max(0, metadata[badgeCountAttr] + direction),\n }),\n );\n }\n\n // Update the items with the given attributes\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n private async makeStatusUpdate(itemOrItems: FeedItemOrItems, type: Status) {\n // Always treat items as a batch to use the corresponding batch endpoint\n const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];\n const itemIds = items.map((item) => item.id);\n\n const result = await this.apiClient.makeRequest({\n method: \"POST\",\n url: `/v1/messages/batch/${type}`,\n data: { message_ids: itemIds },\n });\n\n // Emit the event that these items had their statuses changed\n // Note: we do this after the update to ensure that the server event actually completed\n this.broadcaster.emit(`items:${type}`, { items });\n this.broadcastOverChannel(`items:${type}`, { items });\n\n return result;\n }\n\n private async makeBulkStatusUpdate(type: \"seen\" | \"read\" | \"archive\") {\n // The base scope for the call should take into account all of the options currently\n // set on the feed, as well as being scoped for the current user. We do this so that\n // we ONLY make changes to the messages that are currently in view on this feed, and not\n // all messages that exist.\n const options = {\n user_ids: [this.knock.userId],\n engagement_status:\n this.defaultOptions.status !== \"all\"\n ? this.defaultOptions.status\n : undefined,\n archived: this.defaultOptions.archived,\n has_tenant: this.defaultOptions.has_tenant,\n tenants: this.defaultOptions.tenant\n ? [this.defaultOptions.tenant]\n : undefined,\n };\n\n return await this.apiClient.makeRequest({\n method: \"POST\",\n url: `/v1/channels/${this.feedId}/messages/bulk/${type}`,\n data: options,\n });\n }\n\n private broadcastOverChannel(type: string, payload: any) {\n // The broadcastChannel may not be available in non-browser environments\n if (!this.broadcastChannel) {\n return;\n }\n\n // Here we stringify our payload and try and send as JSON such that we\n // don't get any `An object could not be cloned` errors when trying to broadcast\n try {\n const stringifiedPayload = JSON.parse(JSON.stringify(payload));\n\n this.broadcastChannel.postMessage({\n type,\n payload: stringifiedPayload,\n });\n } catch (e) {\n console.warn(`Could not broadcast ${type}, got error: ${e}`);\n }\n }\n}\n\nexport default Feed;\n"],"file":"feed.js"}
1
+ {"version":3,"sources":["../../../../src/clients/feed/feed.ts"],"names":["EventEmitter2","EventEmitter","createStore","isRequestInFlight","NetworkStatus","feedClientDefaults","archived","Feed","constructor","knock","feedId","options","apiClient","client","userFeedId","buildUserFeedId","store","broadcaster","wildcard","delimiter","defaultOptions","channel","socket","on","resp","onNewMessageReceived","broadcastChannel","self","BroadcastChannel","teardown","leave","removeAllListeners","off","destroy","close","listenForUpdates","isConnected","connect","includes","state","join","__experimentalCrossBrowserUpdates","onmessage","e","data","type","fetch","eventName","callback","getState","markAsSeen","itemOrItems","now","Date","toISOString","optimisticallyPerformStatusUpdate","seen_at","makeStatusUpdate","markAllAsSeen","setState","metadata","items","isViewingOnlyUnseen","status","resetStore","total_count","unseen_count","setMetadata","attrs","itemIds","map","item","id","setItemAttrs","result","makeBulkStatusUpdate","emit","broadcastOverChannel","markAsUnseen","markAsRead","read_at","markAllAsRead","isViewingOnlyUnread","unread_count","markAsUnread","markAsInteracted","interacted_at","markAsArchived","shouldOptimisticallyRemoveItems","normalizedItems","Array","isArray","unseenCount","filter","i","length","unreadCount","updatedMetadata","entriesToSet","setResult","entries","meta","page_info","pageInfo","archived_at","markAllAsArchived","markAsUnarchived","networkStatus","setNetworkStatus","__loadingType","loading","queryParams","undefined","__fetchSource","makeRequest","method","url","userId","params","statusCode","body","error","response","before","opts","shouldSetPage","shouldAppend","after","broadcast","feedEventType","eventPayload","event","fetchNextPage","fetchMore","currentHead","__cursor","badgeCountAttr","direction","startsWith","Math","max","message_ids","user_ids","engagement_status","has_tenant","tenants","tenant","payload","stringifiedPayload","JSON","parse","stringify","postMessage","console","warn"],"mappings":"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","sourcesContent":["import { Channel } from \"phoenix\";\nimport { StoreApi } from \"zustand\";\nimport { EventEmitter2 as EventEmitter } from \"eventemitter2\";\nimport ApiClient from \"../../api\";\nimport createStore from \"./store\";\nimport {\n BindableFeedEvent,\n FeedMessagesReceivedPayload,\n FeedEventCallback,\n FeedEvent,\n FeedItemOrItems,\n FeedStoreState,\n FeedEventPayload,\n FeedRealTimeCallback,\n} from \"./types\";\nimport {\n FeedItem,\n FeedClientOptions,\n FetchFeedOptions,\n FeedResponse,\n FeedMetadata,\n} from \"./interfaces\";\nimport Knock from \"../../knock\";\nimport { isRequestInFlight, NetworkStatus } from \"../../networkStatus\";\n\nexport type Status =\n | \"seen\"\n | \"read\"\n | \"interacted\"\n | \"archived\"\n | \"unseen\"\n | \"unread\"\n | \"unarchived\";\n\n// Default options to apply\nconst feedClientDefaults: Pick<FeedClientOptions, \"archived\"> = {\n archived: \"exclude\",\n};\n\nclass Feed {\n private apiClient: ApiClient;\n private userFeedId: string;\n private channel: Channel;\n private broadcaster: EventEmitter;\n private defaultOptions: FeedClientOptions;\n private broadcastChannel: BroadcastChannel | null;\n\n // The raw store instance, used for binding in React and other environments\n public store: StoreApi<FeedStoreState>;\n\n constructor(\n readonly knock: Knock,\n readonly feedId: string,\n options: FeedClientOptions,\n ) {\n this.apiClient = knock.client();\n this.feedId = feedId;\n this.userFeedId = this.buildUserFeedId();\n this.store = createStore();\n this.broadcaster = new EventEmitter({ wildcard: true, delimiter: \".\" });\n this.defaultOptions = { ...feedClientDefaults, ...options };\n\n this.channel = this.apiClient.socket.channel(\n `feeds:${this.userFeedId}`,\n this.defaultOptions,\n );\n\n this.channel.on(\"new-message\", (resp) => this.onNewMessageReceived(resp));\n\n // Attempt to bind to listen to other events from this feed in different tabs\n // Note: here we ensure `self` is available (it's not in server rendered envs)\n this.broadcastChannel =\n self && \"BroadcastChannel\" in self\n ? new BroadcastChannel(`knock:feed:${this.userFeedId}`)\n : null;\n }\n\n /**\n * Cleans up a feed instance by destroying the store and disconnecting\n * an open socket connection.\n */\n teardown() {\n this.channel.leave();\n this.broadcaster.removeAllListeners();\n this.channel.off(\"new-message\");\n this.store.destroy();\n\n if (this.broadcastChannel) {\n this.broadcastChannel.close();\n }\n }\n\n /*\n Initializes a real-time connection to Knock, connecting the websocket for the\n current ApiClient instance if the socket is not already connected.\n */\n listenForUpdates() {\n // Connect the socket only if we don't already have a connection\n if (!this.apiClient.socket.isConnected()) {\n this.apiClient.socket.connect();\n }\n\n // Only join the channel if we're not already in a joining state\n if ([\"closed\", \"errored\"].includes(this.channel.state)) {\n this.channel.join();\n }\n\n // Opt into receiving updates from _other tabs for the same user / feed_ via the broadcast\n // channel (iff it's enabled and exists)\n if (\n this.broadcastChannel &&\n this.defaultOptions.__experimentalCrossBrowserUpdates === true\n ) {\n this.broadcastChannel.onmessage = (e) => {\n switch (e.data.type) {\n case \"items:archived\":\n case \"items:unarchived\":\n case \"items:seen\":\n case \"items:unseen\":\n case \"items:read\":\n case \"items:unread\":\n case \"items:all_read\":\n case \"items:all_seen\":\n case \"items:all_archived\":\n // When items are updated in any other tab, simply refetch to get the latest state\n // to make sure that the state gets updated accordingly. In the future here we could\n // maybe do this optimistically without the fetch.\n return this.fetch();\n break;\n default:\n return null;\n }\n };\n }\n }\n\n /* Binds a handler to be invoked when event occurs */\n on(\n eventName: BindableFeedEvent,\n callback: FeedEventCallback | FeedRealTimeCallback,\n ) {\n this.broadcaster.on(eventName, callback);\n }\n\n off(\n eventName: BindableFeedEvent,\n callback: FeedEventCallback | FeedRealTimeCallback,\n ) {\n this.broadcaster.off(eventName, callback);\n }\n\n getState() {\n return this.store.getState();\n }\n\n async markAsSeen(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"seen\",\n { seen_at: now },\n \"unseen_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"seen\");\n }\n\n async markAllAsSeen() {\n // To mark all of the messages as seen we:\n // 1. Optimistically update *everything* we have in the store\n // 2. We decrement the `unseen_count` to zero optimistically\n // 3. We issue the API call to the endpoint\n //\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unseen_count` to be what it was.\n //\n // Note: here we optimistically handle the case whereby the feed is scoped to show only `unseen`\n // items by removing everything from view.\n const { getState, setState } = this.store;\n const { metadata, items } = getState();\n\n const isViewingOnlyUnseen = this.defaultOptions.status === \"unseen\";\n\n // If we're looking at the unseen view, then we want to remove all of the items optimistically\n // from the store given that nothing should be visible. We do this by resetting the store state\n // and setting the current metadata counts to 0\n if (isViewingOnlyUnseen) {\n setState((store) =>\n store.resetStore({\n ...metadata,\n total_count: 0,\n unseen_count: 0,\n }),\n );\n } else {\n // Otherwise we want to update the metadata and mark all of the items in the store as seen\n setState((store) => store.setMetadata({ ...metadata, unseen_count: 0 }));\n\n const attrs = { seen_at: new Date().toISOString() };\n const itemIds = items.map((item) => item.id);\n\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"seen\");\n\n this.broadcaster.emit(`items:all_seen`, { items });\n this.broadcastOverChannel(`items:all_seen`, { items });\n\n return result;\n }\n\n async markAsUnseen(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"unseen\",\n { seen_at: null },\n \"unseen_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"unseen\");\n }\n\n async markAsRead(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"read\",\n { read_at: now },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"read\");\n }\n\n async markAllAsRead() {\n // To mark all of the messages as read we:\n // 1. Optimistically update *everything* we have in the store\n // 2. We decrement the `unread_count` to zero optimistically\n // 3. We issue the API call to the endpoint\n //\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unread_count` to be what it was.\n //\n // Note: here we optimistically handle the case whereby the feed is scoped to show only `unread`\n // items by removing everything from view.\n const { getState, setState } = this.store;\n const { metadata, items } = getState();\n\n const isViewingOnlyUnread = this.defaultOptions.status === \"unread\";\n\n // If we're looking at the unread view, then we want to remove all of the items optimistically\n // from the store given that nothing should be visible. We do this by resetting the store state\n // and setting the current metadata counts to 0\n if (isViewingOnlyUnread) {\n setState((store) =>\n store.resetStore({\n ...metadata,\n total_count: 0,\n unread_count: 0,\n }),\n );\n } else {\n // Otherwise we want to update the metadata and mark all of the items in the store as seen\n setState((store) => store.setMetadata({ ...metadata, unread_count: 0 }));\n\n const attrs = { read_at: new Date().toISOString() };\n const itemIds = items.map((item) => item.id);\n\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"read\");\n\n this.broadcaster.emit(`items:all_read`, { items });\n this.broadcastOverChannel(`items:all_read`, { items });\n\n return result;\n }\n\n async markAsUnread(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"unread\",\n { read_at: null },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"unread\");\n }\n\n async markAsInteracted(itemOrItems: FeedItemOrItems) {\n const now = new Date().toISOString();\n this.optimisticallyPerformStatusUpdate(\n itemOrItems,\n \"interacted\",\n {\n read_at: now,\n interacted_at: now,\n },\n \"unread_count\",\n );\n\n return this.makeStatusUpdate(itemOrItems, \"interacted\");\n }\n\n /*\n Marking one or more items as archived should:\n\n - Decrement the badge count for any unread / unseen items\n - Remove the item from the feed list when the `archived` flag is \"exclude\" (default)\n\n TODO: how do we handle rollbacks?\n */\n async markAsArchived(itemOrItems: FeedItemOrItems) {\n const { getState, setState } = this.store;\n const state = getState();\n\n const shouldOptimisticallyRemoveItems =\n this.defaultOptions.archived === \"exclude\";\n\n const normalizedItems = Array.isArray(itemOrItems)\n ? itemOrItems\n : [itemOrItems];\n\n const itemIds: string[] = normalizedItems.map((item) => item.id);\n\n /*\n In the code here we want to optimistically update counts and items\n that are persisted such that we can display updates immediately on the feed\n without needing to make a network request.\n\n Note: right now this does *not* take into account offline handling or any extensive retry\n logic, so rollbacks aren't considered. That probably needs to be a future consideration for\n this library.\n\n Scenarios to consider:\n\n ## Feed scope to archived *only*\n\n - Counts should not be decremented\n - Items should not be removed\n\n ## Feed scoped to exclude archived items (the default)\n\n - Counts should be decremented\n - Items should be removed\n\n ## Feed scoped to include archived items as well\n\n - Counts should not be decremented\n - Items should not be removed\n */\n\n if (shouldOptimisticallyRemoveItems) {\n // If any of the items are unseen or unread, then capture as we'll want to decrement\n // the counts for these in the metadata we have\n const unseenCount = normalizedItems.filter((i) => !i.seen_at).length;\n const unreadCount = normalizedItems.filter((i) => !i.read_at).length;\n\n // Build the new metadata\n const updatedMetadata = {\n ...state.metadata,\n total_count: state.metadata.total_count - normalizedItems.length,\n unseen_count: state.metadata.unseen_count - unseenCount,\n unread_count: state.metadata.unread_count - unreadCount,\n };\n\n // Remove the archiving entries\n const entriesToSet = state.items.filter(\n (item) => !itemIds.includes(item.id),\n );\n\n setState((state) =>\n state.setResult({\n entries: entriesToSet,\n meta: updatedMetadata,\n page_info: state.pageInfo,\n }),\n );\n } else {\n // Mark all the entries being updated as archived either way so the state is correct\n state.setItemAttrs(itemIds, { archived_at: new Date().toISOString() });\n }\n\n return this.makeStatusUpdate(itemOrItems, \"archived\");\n }\n\n async markAllAsArchived() {\n // Note: there is the potential for a race condition here because the bulk\n // update is an async method, so if a new message comes in during this window before\n // the update has been processed we'll effectively reset the `unseen_count` to be what it was.\n const { setState, getState } = this.store;\n const { items } = getState();\n\n // Here if we're looking at a feed that excludes all of the archived items by default then we\n // will want to optimistically remove all of the items from the feed as they are now all excluded\n const shouldOptimisticallyRemoveItems =\n this.defaultOptions.archived === \"exclude\";\n\n if (shouldOptimisticallyRemoveItems) {\n // Reset the store to clear out all of items and reset the badge count\n setState((store) => store.resetStore());\n } else {\n // Mark all the entries being updated as archived either way so the state is correct\n setState((store) => {\n const itemIds = items.map((i) => i.id);\n store.setItemAttrs(itemIds, { archived_at: new Date().toISOString() });\n });\n }\n\n // Issue the API request to the bulk status change API\n const result = await this.makeBulkStatusUpdate(\"archive\");\n\n this.broadcaster.emit(`items:all_archived`, { items });\n this.broadcastOverChannel(`items:all_archived`, { items });\n\n return result;\n }\n\n async markAsUnarchived(itemOrItems: FeedItemOrItems) {\n this.optimisticallyPerformStatusUpdate(itemOrItems, \"unarchived\", {\n archived_at: null,\n });\n\n return this.makeStatusUpdate(itemOrItems, \"unarchived\");\n }\n\n /* Fetches the feed content, appending it to the store */\n async fetch(options: FetchFeedOptions = {}) {\n const { setState, getState } = this.store;\n const { networkStatus } = getState();\n\n // If there's an existing request in flight, then do nothing\n if (isRequestInFlight(networkStatus)) {\n return;\n }\n\n // Set the loading type based on the request type it is\n setState((store) =>\n store.setNetworkStatus(options.__loadingType ?? NetworkStatus.loading),\n );\n\n // Always include the default params, if they have been set\n const queryParams = {\n ...this.defaultOptions,\n ...options,\n // Unset options that should not be sent to the API\n __loadingType: undefined,\n __fetchSource: undefined,\n __experimentalCrossBrowserUpdates: undefined,\n };\n\n const result = await this.apiClient.makeRequest({\n method: \"GET\",\n url: `/v1/users/${this.knock.userId}/feeds/${this.feedId}`,\n params: queryParams,\n });\n\n if (result.statusCode === \"error\" || !result.body) {\n setState((store) => store.setNetworkStatus(NetworkStatus.error));\n\n return {\n status: result.statusCode,\n data: result.error || result.body,\n };\n }\n\n const response = {\n entries: result.body.entries,\n meta: result.body.meta,\n page_info: result.body.page_info,\n };\n\n if (options.before) {\n const opts = { shouldSetPage: false, shouldAppend: true };\n setState((state) => state.setResult(response, opts));\n } else if (options.after) {\n const opts = { shouldSetPage: true, shouldAppend: true };\n setState((state) => state.setResult(response, opts));\n } else {\n setState((state) => state.setResult(response));\n }\n\n // Legacy `messages.new` event, should be removed in a future version\n this.broadcast(\"messages.new\", response);\n\n // Broadcast the appropriate event type depending on the fetch source\n const feedEventType: FeedEvent =\n options.__fetchSource === \"socket\"\n ? \"items.received.realtime\"\n : \"items.received.page\";\n\n const eventPayload = {\n items: response.entries as FeedItem[],\n metadata: response.meta as FeedMetadata,\n event: feedEventType,\n };\n\n this.broadcast(eventPayload.event, eventPayload);\n\n return { data: response, status: result.statusCode };\n }\n\n async fetchNextPage() {\n // Attempts to fetch the next page of results (if we have any)\n const { getState } = this.store;\n const { pageInfo } = getState();\n\n if (!pageInfo.after) {\n // Nothing more to fetch\n return;\n }\n\n this.fetch({\n after: pageInfo.after,\n __loadingType: NetworkStatus.fetchMore,\n });\n }\n\n private broadcast(\n eventName: FeedEvent,\n data: FeedResponse | FeedEventPayload,\n ) {\n this.broadcaster.emit(eventName, data);\n }\n\n // Invoked when a new real-time message comes in from the socket\n private async onNewMessageReceived({\n metadata,\n }: FeedMessagesReceivedPayload) {\n // Handle the new message coming in\n const { getState, setState } = this.store;\n const { items } = getState();\n const currentHead: FeedItem | undefined = items[0];\n // Optimistically set the badge counts\n setState((state) => state.setMetadata(metadata));\n // Fetch the items before the current head (if it exists)\n this.fetch({ before: currentHead?.__cursor, __fetchSource: \"socket\" });\n }\n\n private buildUserFeedId() {\n return `${this.feedId}:${this.knock.userId}`;\n }\n\n private optimisticallyPerformStatusUpdate(\n itemOrItems: FeedItemOrItems,\n type: Status,\n attrs: object,\n badgeCountAttr?: \"unread_count\" | \"unseen_count\",\n ) {\n const { getState, setState } = this.store;\n const itemIds = Array.isArray(itemOrItems)\n ? itemOrItems.map((item) => item.id)\n : [itemOrItems.id];\n\n if (badgeCountAttr) {\n const { metadata } = getState();\n\n // Tnis is a hack to determine the direction of whether we're\n // adding or removing from the badge count\n const direction = type.startsWith(\"un\")\n ? itemIds.length\n : -itemIds.length;\n\n setState((store) =>\n store.setMetadata({\n ...metadata,\n [badgeCountAttr]: Math.max(0, metadata[badgeCountAttr] + direction),\n }),\n );\n }\n\n // Update the items with the given attributes\n setState((store) => store.setItemAttrs(itemIds, attrs));\n }\n\n private async makeStatusUpdate(itemOrItems: FeedItemOrItems, type: Status) {\n // Always treat items as a batch to use the corresponding batch endpoint\n const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];\n const itemIds = items.map((item) => item.id);\n\n const result = await this.apiClient.makeRequest({\n method: \"POST\",\n url: `/v1/messages/batch/${type}`,\n data: { message_ids: itemIds },\n });\n\n // Emit the event that these items had their statuses changed\n // Note: we do this after the update to ensure that the server event actually completed\n this.broadcaster.emit(`items:${type}`, { items });\n this.broadcastOverChannel(`items:${type}`, { items });\n\n return result;\n }\n\n private async makeBulkStatusUpdate(type: \"seen\" | \"read\" | \"archive\") {\n // The base scope for the call should take into account all of the options currently\n // set on the feed, as well as being scoped for the current user. We do this so that\n // we ONLY make changes to the messages that are currently in view on this feed, and not\n // all messages that exist.\n const options = {\n user_ids: [this.knock.userId],\n engagement_status:\n this.defaultOptions.status !== \"all\"\n ? this.defaultOptions.status\n : undefined,\n archived: this.defaultOptions.archived,\n has_tenant: this.defaultOptions.has_tenant,\n tenants: this.defaultOptions.tenant\n ? [this.defaultOptions.tenant]\n : undefined,\n };\n\n return await this.apiClient.makeRequest({\n method: \"POST\",\n url: `/v1/channels/${this.feedId}/messages/bulk/${type}`,\n data: options,\n });\n }\n\n private broadcastOverChannel(type: string, payload: any) {\n // The broadcastChannel may not be available in non-browser environments\n if (!this.broadcastChannel) {\n return;\n }\n\n // Here we stringify our payload and try and send as JSON such that we\n // don't get any `An object could not be cloned` errors when trying to broadcast\n try {\n const stringifiedPayload = JSON.parse(JSON.stringify(payload));\n\n this.broadcastChannel.postMessage({\n type,\n payload: stringifiedPayload,\n });\n } catch (e) {\n console.warn(`Could not broadcast ${type}, got error: ${e}`);\n }\n }\n}\n\nexport default Feed;\n"],"file":"feed.js"}
@@ -2,7 +2,7 @@ import { StoreApi } from "zustand";
2
2
  import { BindableFeedEvent, FeedEventCallback, FeedItemOrItems, FeedStoreState, FeedRealTimeCallback } from "./types";
3
3
  import { FeedClientOptions, FetchFeedOptions } from "./interfaces";
4
4
  import Knock from "../../knock";
5
- export declare type Status = "seen" | "read" | "archived" | "unseen" | "unread" | "unarchived";
5
+ export declare type Status = "seen" | "read" | "interacted" | "archived" | "unseen" | "unread" | "unarchived";
6
6
  declare class Feed {
7
7
  readonly knock: Knock;
8
8
  readonly feedId: string;
@@ -29,6 +29,7 @@ declare class Feed {
29
29
  markAsRead(itemOrItems: FeedItemOrItems): Promise<import("../../api").ApiResponse>;
30
30
  markAllAsRead(): Promise<import("../../api").ApiResponse>;
31
31
  markAsUnread(itemOrItems: FeedItemOrItems): Promise<import("../../api").ApiResponse>;
32
+ markAsInteracted(itemOrItems: FeedItemOrItems): Promise<import("../../api").ApiResponse>;
32
33
  markAsArchived(itemOrItems: FeedItemOrItems): Promise<import("../../api").ApiResponse>;
33
34
  markAllAsArchived(): Promise<import("../../api").ApiResponse>;
34
35
  markAsUnarchived(itemOrItems: FeedItemOrItems): Promise<import("../../api").ApiResponse>;
@@ -1 +1 @@
1
- {"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../../../../src/clients/feed/feed.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAInC,OAAO,EACL,iBAAiB,EAEjB,iBAAiB,EAEjB,eAAe,EACf,cAAc,EAEd,oBAAoB,EACrB,MAAM,SAAS,CAAC;AACjB,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,EAGjB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,MAAM,aAAa,CAAC;AAGhC,oBAAY,MAAM,GACd,MAAM,GACN,MAAM,GACN,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,YAAY,CAAC;AAOjB,cAAM,IAAI;IAYN,QAAQ,CAAC,KAAK,EAAE,KAAK;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IAZzB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,cAAc,CAAoB;IAC1C,OAAO,CAAC,gBAAgB,CAA0B;IAG3C,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;gBAG5B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,iBAAiB;IAwB5B;;;OAGG;IACH,QAAQ;IAeR,gBAAgB;IAyChB,EAAE,CACA,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,iBAAiB,GAAG,oBAAoB;IAKpD,GAAG,CACD,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,iBAAiB,GAAG,oBAAoB;IAKpD,QAAQ;IAIF,UAAU,CAAC,WAAW,EAAE,eAAe;IAYvC,aAAa;IA+Cb,YAAY,CAAC,WAAW,EAAE,eAAe;IAWzC,UAAU,CAAC,WAAW,EAAE,eAAe;IAYvC,aAAa;IA+Cb,YAAY,CAAC,WAAW,EAAE,eAAe;IAmBzC,cAAc,CAAC,WAAW,EAAE,eAAe;IA0E3C,iBAAiB;IAgCjB,gBAAgB,CAAC,WAAW,EAAE,eAAe;IAS7C,KAAK,CAAC,OAAO,GAAE,gBAAqB;;;;IA2EpC,aAAa;IAgBnB,OAAO,CAAC,SAAS;YAQH,oBAAoB;IAalC,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iCAAiC;YAgC3B,gBAAgB;YAmBhB,oBAAoB;IAyBlC,OAAO,CAAC,oBAAoB;CAmB7B;AAED,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../../../../src/clients/feed/feed.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAInC,OAAO,EACL,iBAAiB,EAEjB,iBAAiB,EAEjB,eAAe,EACf,cAAc,EAEd,oBAAoB,EACrB,MAAM,SAAS,CAAC;AACjB,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,EAGjB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,MAAM,aAAa,CAAC;AAGhC,oBAAY,MAAM,GACd,MAAM,GACN,MAAM,GACN,YAAY,GACZ,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,YAAY,CAAC;AAOjB,cAAM,IAAI;IAYN,QAAQ,CAAC,KAAK,EAAE,KAAK;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IAZzB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,cAAc,CAAoB;IAC1C,OAAO,CAAC,gBAAgB,CAA0B;IAG3C,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;gBAG5B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,iBAAiB;IAwB5B;;;OAGG;IACH,QAAQ;IAeR,gBAAgB;IAyChB,EAAE,CACA,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,iBAAiB,GAAG,oBAAoB;IAKpD,GAAG,CACD,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,iBAAiB,GAAG,oBAAoB;IAKpD,QAAQ;IAIF,UAAU,CAAC,WAAW,EAAE,eAAe;IAYvC,aAAa;IA+Cb,YAAY,CAAC,WAAW,EAAE,eAAe;IAWzC,UAAU,CAAC,WAAW,EAAE,eAAe;IAYvC,aAAa;IA+Cb,YAAY,CAAC,WAAW,EAAE,eAAe;IAWzC,gBAAgB,CAAC,WAAW,EAAE,eAAe;IAuB7C,cAAc,CAAC,WAAW,EAAE,eAAe;IA0E3C,iBAAiB;IAgCjB,gBAAgB,CAAC,WAAW,EAAE,eAAe;IAS7C,KAAK,CAAC,OAAO,GAAE,gBAAqB;;;;IA2EpC,aAAa;IAgBnB,OAAO,CAAC,SAAS;YAQH,oBAAoB;IAalC,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iCAAiC;YAgC3B,gBAAgB;YAmBhB,oBAAoB;IAyBlC,OAAO,CAAC,oBAAoB;CAmB7B;AAED,eAAe,IAAI,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knocklabs/client",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "The clientside library for interacting with Knock",
5
5
  "homepage": "https://github.com/knocklabs/knock-client-js",
6
6
  "author": "@knocklabs",