@amityco/ts-sdk 7.22.1-fa4a2e0.0 → 7.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/@types/core/errors.d.ts +2 -1
  2. package/dist/@types/core/errors.d.ts.map +1 -1
  3. package/dist/@types/core/payload.d.ts +0 -1
  4. package/dist/@types/core/payload.d.ts.map +1 -1
  5. package/dist/@types/domains/channel.d.ts +11 -0
  6. package/dist/@types/domains/channel.d.ts.map +1 -1
  7. package/dist/@types/domains/client.d.ts +6 -0
  8. package/dist/@types/domains/client.d.ts.map +1 -1
  9. package/dist/channelRepository/observers/index.d.ts +1 -0
  10. package/dist/channelRepository/observers/index.d.ts.map +1 -1
  11. package/dist/channelRepository/observers/searchChannels/SearchChannelLiveCollectionController.d.ts +14 -0
  12. package/dist/channelRepository/observers/searchChannels/SearchChannelLiveCollectionController.d.ts.map +1 -0
  13. package/dist/channelRepository/observers/searchChannels/SearchChannelPaginationController.d.ts +10 -0
  14. package/dist/channelRepository/observers/searchChannels/SearchChannelPaginationController.d.ts.map +1 -0
  15. package/dist/channelRepository/observers/searchChannels/SearchChannelQueryStreamController.d.ts +13 -0
  16. package/dist/channelRepository/observers/searchChannels/SearchChannelQueryStreamController.d.ts.map +1 -0
  17. package/dist/channelRepository/observers/searchChannels.d.ts +21 -0
  18. package/dist/channelRepository/observers/searchChannels.d.ts.map +1 -0
  19. package/dist/channelRepository/observers/tests/integrations/searchChannels.integration.test.d.ts +2 -0
  20. package/dist/channelRepository/observers/tests/integrations/searchChannels.integration.test.d.ts.map +1 -0
  21. package/dist/client/api/createClient.d.ts.map +1 -1
  22. package/dist/client/api/getForYouFeedSetting.d.ts +17 -0
  23. package/dist/client/api/getForYouFeedSetting.d.ts.map +1 -0
  24. package/dist/client/api/index.d.ts +1 -0
  25. package/dist/client/api/index.d.ts.map +1 -1
  26. package/dist/client/api/setupLoginSubscriptions.d.ts.map +1 -1
  27. package/dist/feedRepository/observers/getForYouFeed/CursorController.d.ts +2 -0
  28. package/dist/feedRepository/observers/getForYouFeed/CursorController.d.ts.map +1 -1
  29. package/dist/feedRepository/observers/getForYouFeed/PaginationController.d.ts +5 -4
  30. package/dist/feedRepository/observers/getForYouFeed/PaginationController.d.ts.map +1 -1
  31. package/dist/index.cjs.js +829 -197
  32. package/dist/index.esm.js +822 -190
  33. package/dist/index.umd.js +2 -2
  34. package/dist/userRepository/api/getAllBlockedUsers.d.ts.map +1 -1
  35. package/dist/userRepository/api/getAllBlockingUsers.d.ts +20 -0
  36. package/dist/userRepository/api/getAllBlockingUsers.d.ts.map +1 -0
  37. package/dist/userRepository/api/index.d.ts +1 -0
  38. package/dist/userRepository/api/index.d.ts.map +1 -1
  39. package/dist/userRepository/api/tests/integration/getAllBlockingUsers.integration.test.d.ts +2 -0
  40. package/dist/userRepository/api/tests/integration/getAllBlockingUsers.integration.test.d.ts.map +1 -0
  41. package/dist/userRepository/relationship/block/utils/blockRealtimeOnLoginHandler.d.ts +12 -0
  42. package/dist/userRepository/relationship/block/utils/blockRealtimeOnLoginHandler.d.ts.map +1 -0
  43. package/dist/userRepository/services/BlockedUserSyncEngine/blockedUserSyncEngine.d.ts +13 -13
  44. package/dist/userRepository/services/BlockedUserSyncEngine/blockedUserSyncEngine.d.ts.map +1 -1
  45. package/dist/userRepository/services/BlockingUserSyncEngine/blockingUserSyncEngine.d.ts +56 -0
  46. package/dist/userRepository/services/BlockingUserSyncEngine/blockingUserSyncEngine.d.ts.map +1 -0
  47. package/dist/userRepository/services/BlockingUserSyncEngine/blockingUserSyncEngineOnLoginHandler.d.ts +3 -0
  48. package/dist/userRepository/services/BlockingUserSyncEngine/blockingUserSyncEngineOnLoginHandler.d.ts.map +1 -0
  49. package/dist/utils/tests/dummy/block.d.ts +16 -0
  50. package/dist/utils/tests/dummy/block.d.ts.map +1 -1
  51. package/package.json +1 -1
package/dist/index.esm.js CHANGED
@@ -298,8 +298,8 @@ var NotificationRolesFilterTypeEnum;
298
298
 
299
299
  function getVersion() {
300
300
  try {
301
- // the string ''v7.22.0-esm'' should be replaced by actual value by @rollup/plugin-replace
302
- return 'v7.22.0-esm';
301
+ // the string ''v7.23.0-esm'' should be replaced by actual value by @rollup/plugin-replace
302
+ return 'v7.23.0-esm';
303
303
  }
304
304
  catch (error) {
305
305
  return '__dev__';
@@ -1956,13 +1956,13 @@ class NetworkActivitiesWatcher {
1956
1956
  this._listener.clear();
1957
1957
  }
1958
1958
  }
1959
- let instance$a;
1959
+ let instance$b;
1960
1960
  var NetworkActivitiesWatcher$1 = {
1961
1961
  getInstance: () => {
1962
- if (!instance$a) {
1963
- instance$a = new NetworkActivitiesWatcher();
1962
+ if (!instance$b) {
1963
+ instance$b = new NetworkActivitiesWatcher();
1964
1964
  }
1965
- return instance$a;
1965
+ return instance$b;
1966
1966
  },
1967
1967
  };
1968
1968
 
@@ -20822,13 +20822,13 @@ class SessionWatcher {
20822
20822
  this._listener.clear();
20823
20823
  }
20824
20824
  }
20825
- let instance$9;
20825
+ let instance$a;
20826
20826
  var SessionWatcher$1 = {
20827
20827
  getInstance: () => {
20828
- if (!instance$9) {
20829
- instance$9 = new SessionWatcher();
20828
+ if (!instance$a) {
20829
+ instance$a = new SessionWatcher();
20830
20830
  }
20831
- return instance$9;
20831
+ return instance$a;
20832
20832
  },
20833
20833
  };
20834
20834
 
@@ -20925,11 +20925,11 @@ class AutoSubscriptionManager {
20925
20925
  this.seed();
20926
20926
  }
20927
20927
  }
20928
- let instance$8 = null;
20928
+ let instance$9 = null;
20929
20929
  const getAutoSubscriptionManager = () => {
20930
- if (!instance$8)
20931
- instance$8 = new AutoSubscriptionManager();
20932
- return instance$8;
20930
+ if (!instance$9)
20931
+ instance$9 = new AutoSubscriptionManager();
20932
+ return instance$9;
20933
20933
  };
20934
20934
  /** Resets the registry to its default baseline when the session ends. */
20935
20935
  const resetAutoSubscriptionsOnLogout = () => onSessionStateChange(state => {
@@ -22153,7 +22153,7 @@ getSubChannel$1.locally = (subChannelId) => {
22153
22153
  };
22154
22154
  };
22155
22155
 
22156
- const getMessagePreviewSetting$1 = async () => {
22156
+ const getMessagePreviewSetting$2 = async () => {
22157
22157
  const client = getActiveClient();
22158
22158
  return client.getMessagePreviewSetting(false);
22159
22159
  };
@@ -22188,7 +22188,7 @@ const isLastestMessageOnChannel = (message) => {
22188
22188
  convertDateStringToTimestamp(cache.createdAt) <= convertDateStringToTimestamp(message.createdAt));
22189
22189
  };
22190
22190
  const handleMessageCreatedOnSubChannel = async (message) => {
22191
- const messagePreviewSetting = await getMessagePreviewSetting$1();
22191
+ const messagePreviewSetting = await getMessagePreviewSetting$2();
22192
22192
  const { channelId, messageId: messagePreviewId, creatorId, createdAt, updatedAt, data, dataType, subChannelId, channelSegment: segment, isDeleted, } = message;
22193
22193
  // 1. get subChannel from cache, if not exist fetch from server
22194
22194
  const subChannelCache = await getSubChannelCache(subChannelId);
@@ -23539,7 +23539,7 @@ const convertMessagePreviewSetting = (chatSetting) => {
23539
23539
  * @category private
23540
23540
  * @async
23541
23541
  */
23542
- const getMessagePreviewSetting = async (refresh = true) => {
23542
+ const getMessagePreviewSetting$1 = async (refresh = true) => {
23543
23543
  var _a;
23544
23544
  const messagePreviewSetting = (_a = pullFromCache([
23545
23545
  'MessagePreviewSetting',
@@ -23560,7 +23560,7 @@ const getMessagePreviewSetting = async (refresh = true) => {
23560
23560
  */
23561
23561
  const initializeMessagePreviewSetting = async () => {
23562
23562
  var _a;
23563
- const newMessagePreviewSetting = await getMessagePreviewSetting();
23563
+ const newMessagePreviewSetting = await getMessagePreviewSetting$1();
23564
23564
  const messagePreviewSetting = (_a = pullFromCache([
23565
23565
  'MessagePreviewSetting',
23566
23566
  ])) === null || _a === void 0 ? void 0 : _a.data;
@@ -23674,6 +23674,33 @@ const getProductCatalogueSetting = async () => {
23674
23674
  };
23675
23675
  /* end_public_function */
23676
23676
 
23677
+ /* begin_public_function
23678
+ id: client.getForYouFeedSetting
23679
+ */
23680
+ /**
23681
+ * ```js
23682
+ * import { Client } from '@amityco/ts-sdk'
23683
+ * const forYouFeedSetting = await Client.getForYouFeedSetting()
23684
+ * ```
23685
+ *
23686
+ * Fetches the network-level {@link Amity.ForYouFeedSetting} — whether the For You
23687
+ * feed feature is enabled for the current network. Use `forYouFeed.enabled` as a
23688
+ * feature gate before querying {@link getForYouFeed}.
23689
+ *
23690
+ * @returns A Promise of {@link Amity.ForYouFeedSetting} object
23691
+ *
23692
+ * @category Client API
23693
+ * @async
23694
+ */
23695
+ const getForYouFeedSetting = async () => {
23696
+ var _a, _b;
23697
+ const client = getActiveClient();
23698
+ const { data } = await client.http.get(`/api/v3/network-settings/for-you-feed`);
23699
+ // Surface only `enabled`; ignore server-side ranking config (scoringConfig, etc.)
23700
+ return { forYouFeed: { enabled: (_b = (_a = data.forYouFeed) === null || _a === void 0 ? void 0 : _a.enabled) !== null && _b !== void 0 ? _b : false } };
23701
+ };
23702
+ /* end_public_function */
23703
+
23677
23704
  const checkUserPermission = (userId, permission) => {
23678
23705
  var _a;
23679
23706
  const user = (_a = pullFromCache(['user', 'get', userId])) === null || _a === void 0 ? void 0 : _a.data;
@@ -24461,13 +24488,13 @@ class AnalyticsEngine {
24461
24488
  this._eventCapturer.resetAllBuckets();
24462
24489
  }
24463
24490
  }
24464
- let instance$7;
24491
+ let instance$8;
24465
24492
  var AnalyticsEngine$1 = {
24466
24493
  getInstance: () => {
24467
- if (!instance$7) {
24468
- instance$7 = new AnalyticsEngine();
24494
+ if (!instance$8) {
24495
+ instance$8 = new AnalyticsEngine();
24469
24496
  }
24470
- return instance$7;
24497
+ return instance$8;
24471
24498
  },
24472
24499
  };
24473
24500
 
@@ -24694,12 +24721,12 @@ class MessageReadReceiptSyncEngine {
24694
24721
  }
24695
24722
  }
24696
24723
  }
24697
- let instance$6 = null;
24724
+ let instance$7 = null;
24698
24725
  var ReadReceiptSyncEngine = {
24699
24726
  getInstance: () => {
24700
- if (!instance$6)
24701
- instance$6 = new MessageReadReceiptSyncEngine();
24702
- return instance$6;
24727
+ if (!instance$7)
24728
+ instance$7 = new MessageReadReceiptSyncEngine();
24729
+ return instance$7;
24703
24730
  },
24704
24731
  };
24705
24732
 
@@ -24953,12 +24980,12 @@ class LegacyMessageReadReceiptSyncEngine {
24953
24980
  }
24954
24981
  }
24955
24982
  }
24956
- let instance$5 = null;
24983
+ let instance$6 = null;
24957
24984
  var LegacyReadReceiptSyncEngine = {
24958
24985
  getInstance: () => {
24959
- if (!instance$5)
24960
- instance$5 = new LegacyMessageReadReceiptSyncEngine();
24961
- return instance$5;
24986
+ if (!instance$6)
24987
+ instance$6 = new LegacyMessageReadReceiptSyncEngine();
24988
+ return instance$6;
24962
24989
  },
24963
24990
  };
24964
24991
 
@@ -25204,12 +25231,12 @@ class ObjectResolverEngine {
25204
25231
  this.stopResolver();
25205
25232
  }
25206
25233
  }
25207
- let instance$4 = null;
25234
+ let instance$5 = null;
25208
25235
  var ObjectResolverEngine$1 = {
25209
25236
  getInstance: () => {
25210
- if (!instance$4)
25211
- instance$4 = new ObjectResolverEngine();
25212
- return instance$4;
25237
+ if (!instance$5)
25238
+ instance$5 = new ObjectResolverEngine();
25239
+ return instance$5;
25213
25240
  },
25214
25241
  };
25215
25242
 
@@ -25359,13 +25386,13 @@ class LiveReactionSyncEngine {
25359
25386
  this.stopReactionsSync();
25360
25387
  }
25361
25388
  }
25362
- let instance$3;
25389
+ let instance$4;
25363
25390
  var ReactionSyncEngine = {
25364
25391
  getInstance: () => {
25365
- if (!instance$3) {
25366
- instance$3 = new LiveReactionSyncEngine();
25392
+ if (!instance$4) {
25393
+ instance$4 = new LiveReactionSyncEngine();
25367
25394
  }
25368
- return instance$3;
25395
+ return instance$4;
25369
25396
  },
25370
25397
  };
25371
25398
 
@@ -25395,19 +25422,20 @@ function prepareBlockedUserPayload(response) {
25395
25422
  }), users: users.map(convertRawUserToInternalUser) });
25396
25423
  }
25397
25424
 
25398
- const BLOCK_LIST_LIMIT = 100;
25399
- const TTL_MS = 5 * 60 * 1000; // 5 minutes
25425
+ const BLOCK_LIST_LIMIT$1 = 100;
25426
+ const TTL_MS$1 = 5 * 60 * 1000; // 5 minutes
25400
25427
  /**
25401
25428
  * Session-scoped singleton engine that manages TTL-based fetching and caching
25402
25429
  * of blocked users. Provides a lazy `ensureFetched()` gate for the
25403
25430
  * `getAllBlockedUsers()` API.
25404
25431
  *
25405
25432
  * Key behaviours:
25406
- * - `establish()` is a no-op — fetch is lazy, triggered only by consumer call
25407
- * - `destroy()` resets `lastFetchedAt` to null (ensures fresh fetch on next session)
25433
+ * - `onSessionEstablished()` is a no-op — fetch is lazy, triggered only by consumer call
25434
+ * - `onSessionDestroyed()` resets `lastFetchedAt` to null (ensures fresh fetch on next session)
25408
25435
  * - `ensureFetched()` fetches from server only when cache is expired or never fetched
25409
25436
  * - `lastFetchedAt` is only updated on successful fetch
25410
- * - `blockedUserIds` is kept in sync with each successful fetch
25437
+ * - reads query the follow cache live, so block/unblock changes are reflected
25438
+ * even within the TTL window
25411
25439
  *
25412
25440
  * @internal
25413
25441
  */
@@ -25415,12 +25443,7 @@ class BlockedUserSyncEngine {
25415
25443
  constructor() {
25416
25444
  /** Epoch ms of last successful fetch. null = never fetched in this session. */
25417
25445
  this.lastFetchedAt = null;
25418
- /** Ordered list of userId strings from the most recent successful fetch. */
25419
- this.blockedUserIds = [];
25420
25446
  }
25421
- // ---------------------------------------------------------------------------
25422
- // SessionComponent lifecycle
25423
- // ---------------------------------------------------------------------------
25424
25447
  /** No-op — fetch is lazy, triggered by consumer calling getAllBlockedUsers(). */
25425
25448
  // eslint-disable-next-line class-methods-use-this
25426
25449
  onSessionEstablished() {
@@ -25429,24 +25452,17 @@ class BlockedUserSyncEngine {
25429
25452
  /** Resets state so the next session starts with a cold cache. */
25430
25453
  onSessionDestroyed() {
25431
25454
  this.lastFetchedAt = null;
25432
- this.blockedUserIds = [];
25433
25455
  }
25434
25456
  /** No-op for this engine. */
25435
25457
  // eslint-disable-next-line class-methods-use-this
25436
25458
  onTokenExpired() {
25437
25459
  // intentionally empty
25438
25460
  }
25439
- // ---------------------------------------------------------------------------
25440
- // Cache helpers
25441
- // ---------------------------------------------------------------------------
25442
25461
  isCacheExpired() {
25443
25462
  if (this.lastFetchedAt === null)
25444
25463
  return true;
25445
- return Date.now() - this.lastFetchedAt > TTL_MS;
25464
+ return Date.now() - this.lastFetchedAt > TTL_MS$1;
25446
25465
  }
25447
- // ---------------------------------------------------------------------------
25448
- // Core fetch gate
25449
- // ---------------------------------------------------------------------------
25450
25466
  /**
25451
25467
  * Ensures the local store is populated with fresh blocked-user data.
25452
25468
  *
@@ -25462,52 +25478,50 @@ class BlockedUserSyncEngine {
25462
25478
  if (!this.isCacheExpired())
25463
25479
  return;
25464
25480
  const client = getActiveClient();
25465
- const { data } = await client.http.get('/api/v4/me/user-blocks', { params: { options: { limit: BLOCK_LIST_LIMIT }, isDeleted: false } });
25481
+ const { data } = await client.http.get('/api/v4/me/user-blocks', { params: { options: { limit: BLOCK_LIST_LIMIT$1 }, isDeleted: false } });
25466
25482
  const cachedAt = client.cache && Date.now();
25467
25483
  const payload = prepareBlockedUserPayload(data);
25468
25484
  if (client.cache) {
25469
25485
  ingestInCache(payload, { cachedAt });
25470
25486
  }
25471
- // Keep the ordered list of blocked user IDs for getCachedUsers()
25472
- this.blockedUserIds = payload.users.map(u => u.userId);
25473
25487
  // Only update timestamp on success — failure leaves it unchanged so the
25474
25488
  // next call retries.
25475
25489
  this.lastFetchedAt = Date.now();
25476
25490
  }
25477
- // ---------------------------------------------------------------------------
25478
- // Local store read
25479
- // ---------------------------------------------------------------------------
25480
25491
  /**
25481
- * Returns blocked {@link Amity.InternalUser} objects from the in-memory cache.
25482
- *
25483
- * Applies the spec-mandated filter:
25484
- * - Only users whose `isDeleted` is false or null
25485
- * - Hard limit of 100 results
25492
+ * Returns the blocked users by querying the follow cache live — the outgoing
25493
+ * direction (`from === me`, `status === 'blocked'`). Reading the cache (not a
25494
+ * fetched snapshot) means `blockUser()` / `unblockUser()` changes are reflected
25495
+ * even within the TTL window.
25486
25496
  *
25487
- * This always reads the latest local state, so changes made by `blockUser()`
25488
- * and `unblockUser()` are reflected even within the TTL window.
25497
+ * Applies the spec-mandated query:
25498
+ * - filter `from === currentUserId`, `status === 'blocked'`, blocked user not deleted
25499
+ * - sort by `updatedAt` DESC
25500
+ * - hard limit of 100 results
25489
25501
  */
25502
+ // eslint-disable-next-line class-methods-use-this
25490
25503
  getCachedUsers() {
25504
+ var _a;
25491
25505
  const client = getActiveClient();
25492
- if (!client.cache) {
25493
- // No cache available — fall back to the in-memory list from the last fetch
25506
+ if (!client.cache)
25494
25507
  return [];
25495
- }
25496
- return this.blockedUserIds
25497
- .map(id => { var _a; return (_a = pullFromCache(['user', 'get', id])) === null || _a === void 0 ? void 0 : _a.data; })
25508
+ const { userId } = client;
25509
+ return ((_a = queryCache(['follow', 'get'])) !== null && _a !== void 0 ? _a : [])
25510
+ .map(entry => entry.data)
25511
+ .filter(follow => (follow === null || follow === void 0 ? void 0 : follow.status) === 'blocked' && follow.from === userId)
25512
+ .sort((a, b) => { var _a, _b; return (((_a = a.updatedAt) !== null && _a !== void 0 ? _a : '') < ((_b = b.updatedAt) !== null && _b !== void 0 ? _b : '') ? 1 : -1); })
25513
+ .map(follow => { var _a; return (_a = pullFromCache(['user', 'get', follow.to])) === null || _a === void 0 ? void 0 : _a.data; })
25498
25514
  .filter((user) => user != null && user.isDeleted !== true)
25499
- .slice(0, BLOCK_LIST_LIMIT);
25515
+ .slice(0, BLOCK_LIST_LIMIT$1)
25516
+ .map(userLinkedObject);
25500
25517
  }
25501
25518
  }
25502
- // ---------------------------------------------------------------------------
25503
- // Module-level singleton
25504
- // ---------------------------------------------------------------------------
25505
- let instance$2 = null;
25519
+ let instance$3 = null;
25506
25520
  var BlockedUserSyncEngine$1 = {
25507
25521
  getInstance: () => {
25508
- if (!instance$2)
25509
- instance$2 = new BlockedUserSyncEngine();
25510
- return instance$2;
25522
+ if (!instance$3)
25523
+ instance$3 = new BlockedUserSyncEngine();
25524
+ return instance$3;
25511
25525
  },
25512
25526
  };
25513
25527
 
@@ -25529,6 +25543,224 @@ var blockedUserSyncEngineOnLoginHandler = () => {
25529
25543
  };
25530
25544
  };
25531
25545
 
25546
+ function prepareBlockingUserPayload(response) {
25547
+ const { users, follows } = response, rest = __rest(response, ["users", "follows"]);
25548
+ return Object.assign(Object.assign({}, rest), { follows: follows.map(follow => {
25549
+ const followUser = users.find(user => user.userId === follow.from);
25550
+ return Object.assign(Object.assign({}, follow), { user: convertRawUserToInternalUser(followUser) });
25551
+ }), users: users.map(convertRawUserToInternalUser) });
25552
+ }
25553
+
25554
+ const BLOCK_LIST_LIMIT = 100;
25555
+ const TTL_MS = 5 * 60 * 1000; // 5 minutes
25556
+ /**
25557
+ * Session-scoped singleton engine that manages TTL-based fetching and caching
25558
+ * of blocking users (the "blocked-by" list — users who blocked the current
25559
+ * user). Provides a lazy `ensureFetched()` gate for the `getAllBlockingUsers()`
25560
+ * API. Directional inverse of {@link BlockedUserSyncEngine}.
25561
+ *
25562
+ * Key behaviours:
25563
+ * - `onSessionEstablished()` is a no-op — fetch is lazy, triggered only by consumer call
25564
+ * - `onSessionDestroyed()` resets `lastFetchedAt` to null (ensures fresh fetch on next session)
25565
+ * - `ensureFetched()` fetches from server only when cache is expired or never fetched
25566
+ * - `lastFetchedAt` is only updated on successful fetch
25567
+ * - reads query the follow cache live, so block/unblock changes are reflected
25568
+ * even within the TTL window
25569
+ *
25570
+ * @internal
25571
+ */
25572
+ class BlockingUserSyncEngine {
25573
+ constructor() {
25574
+ /** Epoch ms of last successful fetch. null = never fetched in this session. */
25575
+ this.lastFetchedAt = null;
25576
+ }
25577
+ /** No-op — fetch is lazy, triggered by consumer calling getAllBlockingUsers(). */
25578
+ // eslint-disable-next-line class-methods-use-this
25579
+ onSessionEstablished() {
25580
+ // intentionally empty
25581
+ }
25582
+ /** Resets state so the next session starts with a cold cache. */
25583
+ onSessionDestroyed() {
25584
+ this.lastFetchedAt = null;
25585
+ }
25586
+ /** No-op for this engine. */
25587
+ // eslint-disable-next-line class-methods-use-this
25588
+ onTokenExpired() {
25589
+ // intentionally empty
25590
+ }
25591
+ isCacheExpired() {
25592
+ if (this.lastFetchedAt === null)
25593
+ return true;
25594
+ return Date.now() - this.lastFetchedAt > TTL_MS;
25595
+ }
25596
+ /**
25597
+ * Ensures the local store is populated with fresh blocking-user data.
25598
+ *
25599
+ * - If the cache is still within the 5-minute TTL window: resolves immediately
25600
+ * (no server call).
25601
+ * - If the cache is expired (or never fetched): fetches from the server,
25602
+ * persists the payload to the cache, and updates `lastFetchedAt`.
25603
+ *
25604
+ * On failure the error propagates to the caller and `lastFetchedAt` is NOT
25605
+ * updated, so the next call will retry.
25606
+ */
25607
+ async ensureFetched() {
25608
+ if (!this.isCacheExpired())
25609
+ return;
25610
+ const client = getActiveClient();
25611
+ const { data } = await client.http.get('/api/v4/me/blockers', { params: { options: { limit: BLOCK_LIST_LIMIT }, isDeleted: false } });
25612
+ const cachedAt = client.cache && Date.now();
25613
+ const payload = prepareBlockingUserPayload(data);
25614
+ if (client.cache) {
25615
+ ingestInCache(payload, { cachedAt });
25616
+ }
25617
+ // Only update timestamp on success — failure leaves it unchanged so the
25618
+ // next call retries.
25619
+ this.lastFetchedAt = Date.now();
25620
+ }
25621
+ /**
25622
+ * Returns the "blocked-by" users by querying the follow cache live — the
25623
+ * incoming direction (`to === me`, `status === 'blocked'`). Reading the cache
25624
+ * (not a fetched snapshot) means RTE `user.didBlock` / `user.didUnblock`
25625
+ * changes are reflected even within the TTL window.
25626
+ *
25627
+ * Applies the spec-mandated query (REQ-012/013/014):
25628
+ * - filter `to === currentUserId`, `status === 'blocked'`, blocker not deleted
25629
+ * - sort by `updatedAt` DESC
25630
+ * - hard limit of 100 results
25631
+ */
25632
+ // eslint-disable-next-line class-methods-use-this
25633
+ getCachedUsers() {
25634
+ var _a;
25635
+ const client = getActiveClient();
25636
+ if (!client.cache)
25637
+ return [];
25638
+ const { userId } = client;
25639
+ return ((_a = queryCache(['follow', 'get'])) !== null && _a !== void 0 ? _a : [])
25640
+ .map(entry => entry.data)
25641
+ .filter(follow => (follow === null || follow === void 0 ? void 0 : follow.status) === 'blocked' && follow.to === userId)
25642
+ .sort((a, b) => { var _a, _b; return (((_a = a.updatedAt) !== null && _a !== void 0 ? _a : '') < ((_b = b.updatedAt) !== null && _b !== void 0 ? _b : '') ? 1 : -1); })
25643
+ .map(follow => { var _a; return (_a = pullFromCache(['user', 'get', follow.from])) === null || _a === void 0 ? void 0 : _a.data; })
25644
+ .filter((user) => user != null && user.isDeleted !== true)
25645
+ .slice(0, BLOCK_LIST_LIMIT)
25646
+ .map(userLinkedObject);
25647
+ }
25648
+ }
25649
+ let instance$2 = null;
25650
+ var BlockingUserSyncEngine$1 = {
25651
+ getInstance: () => {
25652
+ if (!instance$2)
25653
+ instance$2 = new BlockingUserSyncEngine();
25654
+ return instance$2;
25655
+ },
25656
+ };
25657
+
25658
+ var blockingUserSyncEngineOnLoginHandler = () => {
25659
+ const blockingUserSyncEngine = BlockingUserSyncEngine$1.getInstance();
25660
+ onSessionStateChange(state => {
25661
+ if (state === "established" /* Amity.SessionStates.ESTABLISHED */) {
25662
+ blockingUserSyncEngine.onSessionEstablished();
25663
+ }
25664
+ else if (state === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
25665
+ blockingUserSyncEngine.onTokenExpired();
25666
+ }
25667
+ else {
25668
+ blockingUserSyncEngine.onSessionDestroyed();
25669
+ }
25670
+ });
25671
+ return () => {
25672
+ blockingUserSyncEngine.onSessionDestroyed();
25673
+ };
25674
+ };
25675
+
25676
+ function prepareFollowersPayload(response) {
25677
+ const { users, follows } = response, rest = __rest(response, ["users", "follows"]);
25678
+ return Object.assign(Object.assign({}, rest), { follows, users: users.map(convertRawUserToInternalUser) });
25679
+ }
25680
+ function prepareFollowingsPayload(response) {
25681
+ const { users, follows } = response, rest = __rest(response, ["users", "follows"]);
25682
+ return Object.assign(Object.assign({}, rest), { follows, users: users.map(convertRawUserToInternalUser) });
25683
+ }
25684
+ function prepareFollowStatusPayload(response) {
25685
+ const { follows } = response, rest = __rest(response, ["follows"]);
25686
+ return Object.assign(Object.assign({}, rest), { follows });
25687
+ }
25688
+
25689
+ /**
25690
+ * Subscribes to a block MQTT event (`user.didBlock` / `user.didUnblock`),
25691
+ * ingests the carried `FollowersPayload` (follows + users) into the cache so
25692
+ * the block-relationship rows (`['follow', 'get', from#to]`) and user rows are
25693
+ * kept current, then forwards the affected {@link Amity.FollowStatus} to the
25694
+ * caller.
25695
+ *
25696
+ * @hidden
25697
+ */
25698
+ const createBlockEventSubscriber = (event, callback) => {
25699
+ const client = getActiveClient();
25700
+ const filter = (data) => {
25701
+ const payload = prepareFollowersPayload(data);
25702
+ if (client.cache) {
25703
+ ingestInCache(payload);
25704
+ }
25705
+ callback(payload.follows[0]);
25706
+ };
25707
+ return createEventSubscriber(client, event, event, filter);
25708
+ };
25709
+
25710
+ /**
25711
+ * ```js
25712
+ * import { onUserDidBlock } from '@amityco/ts-sdk'
25713
+ * const dispose = onUserDidBlock(status => {
25714
+ * // ...
25715
+ * })
25716
+ * ```
25717
+ *
25718
+ * Fired when a block relationship is created in real time — either a user
25719
+ * blocks the current user (incoming) or the current user blocks someone on
25720
+ * another device (outgoing). The local block-relationship store is updated
25721
+ * before the callback runs.
25722
+ *
25723
+ * @param callback The function to call when the event was fired
25724
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
25725
+ *
25726
+ * @category Block Events
25727
+ */
25728
+ const onUserDidBlock = (callback) => createBlockEventSubscriber('user.didBlock', callback);
25729
+
25730
+ /**
25731
+ * ```js
25732
+ * import { onUserDidUnblock } from '@amityco/ts-sdk'
25733
+ * const dispose = onUserDidUnblock(status => {
25734
+ * // ...
25735
+ * })
25736
+ * ```
25737
+ *
25738
+ * Fired when a block relationship is removed in real time — either a user
25739
+ * unblocks the current user (incoming) or the current user unblocks someone on
25740
+ * another device (outgoing). The local block-relationship store is updated
25741
+ * before the callback runs.
25742
+ *
25743
+ * @param callback The function to call when the event was fired
25744
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
25745
+ *
25746
+ * @category Block Events
25747
+ */
25748
+ const onUserDidUnblock = (callback) => createBlockEventSubscriber('user.didUnblock', callback);
25749
+
25750
+ /**
25751
+ * Keeps the follow cache current for incoming/outgoing block changes for the
25752
+ * whole session — the ingest happens as a side effect inside
25753
+ * createBlockEventSubscriber, so the one-shot `getAllBlockedUsers()` /
25754
+ * `getAllBlockingUsers()` reflect RTE block/unblock within the TTL window.
25755
+ *
25756
+ * Registered via `setupLoginSubscriptions`; the returned unsubscriber is torn
25757
+ * down on logout.
25758
+ */
25759
+ var blockRealtimeOnLoginHandler = () => {
25760
+ const disposers = [onUserDidBlock(() => { }), onUserDidUnblock(() => { })];
25761
+ return () => disposers.forEach(dispose => dispose());
25762
+ };
25763
+
25532
25764
  class CursorController {
25533
25765
  constructor(networkId, userId) {
25534
25766
  this.networkId = networkId;
@@ -25568,7 +25800,11 @@ class CursorController {
25568
25800
  const parsed = JSON.parse(raw);
25569
25801
  if (typeof (parsed === null || parsed === void 0 ? void 0 : parsed.cursor) !== 'string' || typeof (parsed === null || parsed === void 0 ? void 0 : parsed.expiredAt) !== 'number')
25570
25802
  return null;
25571
- return { cursor: parsed.cursor, expiredAt: parsed.expiredAt };
25803
+ return {
25804
+ cursor: parsed.cursor,
25805
+ expiredAt: parsed.expiredAt,
25806
+ reachedEndOfFeed: parsed.reachedEndOfFeed === true,
25807
+ };
25572
25808
  }
25573
25809
  catch (_a) {
25574
25810
  return null;
@@ -25577,6 +25813,15 @@ class CursorController {
25577
25813
  async set(value) {
25578
25814
  await setItem(this.key, JSON.stringify(value));
25579
25815
  }
25816
+ async markReachedEndOfFeed(expiredAt) {
25817
+ var _a;
25818
+ const stored = await this.get();
25819
+ await this.set({
25820
+ cursor: (_a = stored === null || stored === void 0 ? void 0 : stored.cursor) !== null && _a !== void 0 ? _a : '',
25821
+ expiredAt,
25822
+ reachedEndOfFeed: true,
25823
+ });
25824
+ }
25580
25825
  async clear() {
25581
25826
  await setItem(this.key, '');
25582
25827
  }
@@ -25771,7 +26016,7 @@ const setupLoginSubscriptions = (unsubWatcher) => {
25771
26016
  // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
25772
26017
  // the channel because currently backend can't handle this, so every time a user is banned from
25773
26018
  // a channel or the channel is deleted the channel's unread count will not be reset to zero
25774
- onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler(), reactionSyncEngineOnLoginHandler(), blockedUserSyncEngineOnLoginHandler(), resetAutoSubscriptionsOnLogout(), CursorController.clearOnLogout());
26019
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler(), reactionSyncEngineOnLoginHandler(), blockedUserSyncEngineOnLoginHandler(), blockingUserSyncEngineOnLoginHandler(), blockRealtimeOnLoginHandler(), resetAutoSubscriptionsOnLogout(), CursorController.clearOnLogout());
25775
26020
  if (client.useLegacyUnreadCount) {
25776
26021
  subscriptions.push(readReceiptSyncEngineOnLoginHandler());
25777
26022
  }
@@ -26856,12 +27101,13 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
26856
27101
  getSocialSettings,
26857
27102
  getChatSettings,
26858
27103
  getVisitorDeviceId: getDeviceId,
26859
- getMessagePreviewSetting,
27104
+ getMessagePreviewSetting: getMessagePreviewSetting$1,
26860
27105
  use: () => setActiveClient(client),
26861
27106
  isUnreadCountEnabled,
26862
27107
  useLegacyUnreadCount,
26863
27108
  getMarkerSyncConsistentMode,
26864
27109
  getProductCatalogueSetting,
27110
+ getForYouFeedSetting,
26865
27111
  /**
26866
27112
  * Prefix for the deviceId key in the local storage or async storage.
26867
27113
  * This is allow user to have multiple SDK client and Mqtt client within the same app.
@@ -27937,6 +28183,7 @@ var index$s = /*#__PURE__*/Object.freeze({
27937
28183
  getSocialSettings: getSocialSettings,
27938
28184
  getShareableLinkConfiguration: getShareableLinkConfiguration,
27939
28185
  getProductCatalogueSetting: getProductCatalogueSetting,
28186
+ getForYouFeedSetting: getForYouFeedSetting,
27940
28187
  loginAsVisitor: loginAsVisitor,
27941
28188
  loginAsBot: loginAsBot,
27942
28189
  getCurrentUser: getCurrentUser,
@@ -27966,19 +28213,6 @@ var index$s = /*#__PURE__*/Object.freeze({
27966
28213
  getMarkerSyncConsistentMode: getMarkerSyncConsistentMode
27967
28214
  });
27968
28215
 
27969
- function prepareFollowersPayload(response) {
27970
- const { users, follows } = response, rest = __rest(response, ["users", "follows"]);
27971
- return Object.assign(Object.assign({}, rest), { follows, users: users.map(convertRawUserToInternalUser) });
27972
- }
27973
- function prepareFollowingsPayload(response) {
27974
- const { users, follows } = response, rest = __rest(response, ["users", "follows"]);
27975
- return Object.assign(Object.assign({}, rest), { follows, users: users.map(convertRawUserToInternalUser) });
27976
- }
27977
- function prepareFollowStatusPayload(response) {
27978
- const { follows } = response, rest = __rest(response, ["follows"]);
27979
- return Object.assign(Object.assign({}, rest), { follows });
27980
- }
27981
-
27982
28216
  /* begin_public_function
27983
28217
  id: user.relationship.block
27984
28218
  */
@@ -28054,67 +28288,6 @@ const unBlockUser = async (userId) => {
28054
28288
  };
28055
28289
  /* end_public_function */
28056
28290
 
28057
- /**
28058
- * Subscribes to a block MQTT event (`user.didBlock` / `user.didUnblock`),
28059
- * ingests the carried `FollowersPayload` (follows + users) into the cache so
28060
- * the block-relationship rows (`['follow', 'get', from#to]`) and user rows are
28061
- * kept current, then forwards the affected {@link Amity.FollowStatus} to the
28062
- * caller.
28063
- *
28064
- * @hidden
28065
- */
28066
- const createBlockEventSubscriber = (event, callback) => {
28067
- const client = getActiveClient();
28068
- const filter = (data) => {
28069
- const payload = prepareFollowersPayload(data);
28070
- if (client.cache) {
28071
- ingestInCache(payload);
28072
- }
28073
- callback(payload.follows[0]);
28074
- };
28075
- return createEventSubscriber(client, event, event, filter);
28076
- };
28077
-
28078
- /**
28079
- * ```js
28080
- * import { onUserDidBlock } from '@amityco/ts-sdk'
28081
- * const dispose = onUserDidBlock(status => {
28082
- * // ...
28083
- * })
28084
- * ```
28085
- *
28086
- * Fired when a block relationship is created in real time — either a user
28087
- * blocks the current user (incoming) or the current user blocks someone on
28088
- * another device (outgoing). The local block-relationship store is updated
28089
- * before the callback runs.
28090
- *
28091
- * @param callback The function to call when the event was fired
28092
- * @returns an {@link Amity.Unsubscriber} function to stop listening
28093
- *
28094
- * @category Block Events
28095
- */
28096
- const onUserDidBlock = (callback) => createBlockEventSubscriber('user.didBlock', callback);
28097
-
28098
- /**
28099
- * ```js
28100
- * import { onUserDidUnblock } from '@amityco/ts-sdk'
28101
- * const dispose = onUserDidUnblock(status => {
28102
- * // ...
28103
- * })
28104
- * ```
28105
- *
28106
- * Fired when a block relationship is removed in real time — either a user
28107
- * unblocks the current user (incoming) or the current user unblocks someone on
28108
- * another device (outgoing). The local block-relationship store is updated
28109
- * before the callback runs.
28110
- *
28111
- * @param callback The function to call when the event was fired
28112
- * @returns an {@link Amity.Unsubscriber} function to stop listening
28113
- *
28114
- * @category Block Events
28115
- */
28116
- const onUserDidUnblock = (callback) => createBlockEventSubscriber('user.didUnblock', callback);
28117
-
28118
28291
  /* begin_public_function
28119
28292
  id: user.relationship.follow
28120
28293
  */
@@ -30048,7 +30221,7 @@ const getWatchSessionStorage = () => {
30048
30221
  return storageInstance;
30049
30222
  };
30050
30223
 
30051
- const privateKey = "MIIEpQIBAAKCAQEAwAEc/oZgYIvKSUG/C3mONYLR4ZPgAjMEX4bJ+xqqakUDRtqlNO+eZs2blQ1Ko0DBkqPExyQezvjibH5W2UZBV5RaBTlTcNVKTToMBEGesAfaEcM3qUyQHxdbFYZv6P4sb14dcwxTQ8usmaV8ooiR1Fcaso5ZWYcZ8Hb46FbQ7OoVumsBtPWwfZ4f003o5VCl6AIM6lcLv9UDLlFVYhE+PeXpRHtfWlGqxMvqC9oinlwhL6nWv6VjQXW4nhcib72dPBzfHT7k/PMKto2SxALYdb68ENiAGuJLWi3AUHSyYCJK2w7wIlWfJUAI0v26ub10IpExr6D5QuW2577jjP93iwIDAQABAoIBAFWfqXhwIIatkFY+9Z1+ZcbDQimgsmMIsUiQaX6Lk7e0cxOj6czDlxYtVtaPiNtow2pLkjNkjkCqiP7tEHnwdK9DvylZOTa2R15NJpK3WLcTqVIGhsn/FL5owfvFah6zSsmXZParZm5zY9NZE03ALZhOB9/cz0e3kf/EbpfeL2mW7MApyiUt5i09ycchroOpcWp73ipIxvgigtZyUGFmsQicWhUs28F0D7w4Qfk76yG3nqXeb+BAMhCaIaa/k/aAxhiZG/ygEQWQrcC8gfe+jyicMAQPDEVS9YuUMGsLjIjKuVLZzp2xirQnhc2i2zVNEIvG6soprPOBEMQugzrtX5ECgYEA3b7KAbBIbDl1e4ZSCWhHdHkiWVZHaopsR/LhqDDNhXjWjq3AesgV6k0j9EdziMn/HmmOso0bz99GTV3JZf4A9ztTLumJlkHbdVtlgOqSjrFLj12rH9KXTheyIhWSpUmm8+WB1xasFbqpvJaGo7F3pd2Fqj1XR4mp5BO7c/t7LJ0CgYEA3aouEzXQ9THRKYocdfY69EI1Il1t/d/RSqqd9BxEjxBgxkM13ZiYIn/R4WW/nCUrlmhxG44Aa2Gob4Ahfsui2xKTg/g/3Zk/rAxAEGkfOLGoenaJMD41fH4wUq3FRYwkvnaMb9Hd6f/TlBHslIRa2NN58bSBGJCyBP2b59+2+EcCgYEAixDVRXvV37GlYUOa/XVdosk5Zoe6oDGRuQm0xbNdoUBoZvDHDvme7ONWEiQha/8qtVsD+CyQ7awcPfb8kK9c0bBt+bTS6d4BkTcxkEkMgtrkBVR8Nqfu5jXsLH4VCv4G61zbMhZw8+ut+az5YX2yCN7Frj9sFlxapMRPQmzMEe0CgYEAumsAzM8ZqNv4mAK65Mnr0rhLj1cbxcKRdUYACOgtEFQpzxN/HZnTeFAe5nx3pI3uFlRHq3DFEYnT6dHMWaJQmAULYpVIwMi9L6gtyJ9fzoI6uqMtxRDMUqKdaSsTGOY/kJ6KhQ/unXi1K3XXjR+yd1+C0q+HUm1+CYxvrZYLfskCgYEArsEy+IQOiqniJ0NE2vVUF+UK/IRZaic9YKcpov5Ot7Vvzm/MnnW4N1ljVskocETBWMmPUvNSExVjPebi+rxd8fa5kY8BJScPTzMFbunZn/wjtGdcM10qdlVQ9doG61A/9P3ezFKCfS4AvF/H/59LcSx2Bh28fp3/efiVIOpVd4Y=";
30224
+ const privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHo80SecH7FuF2\nhFYnb+l26/VN8UMLXAQFLnxciNTEwkGVFMpdezlH8rU2HtUJL4RETogbAOLVY0XM\njs6sPn8G1nALmh9qeDpUtVqFOVtBHxEZ910TLOtQiunjqJKO5nWdqZ71EC3OFluR\niGQkO84BiIFbv37ub7xl3S8XarbtKoLcyVpkDHi+1wx1pgCAn6gtBUgckPL5NR8j\nLseabl3HAXQfhTCKo4tmOFM2Dxwl1IUMmIJrJg/aIU/U0tj/1Eoo7mG0JcNWX19l\nW3EecCbi0ncCJOrkUdwlBrcjaMayaX/ubEwyUeTGiLdyc4L3GRLHjyK8xgVNXRMH\nbZWJ2a5NAgMBAAECggEASxuE+35zTFO/XydKgmvIGcWL9FbgMlXb7Vcf0nBoG945\nbiz0NVc2paraIhJXc608xbYF3qLmtAE1MVBI0ORyRdBHNxY024l/6H6SH60Ed+uI\nM4ysp5ourY6Vj+DLwpdRiI9YDjqYAQDIUmhNxJP7XPhOMoZI6st+xZQBM34ic/bv\nAMSJm9OZphSp3+qXVkFZztr2mxD2EZSJJLYxi8BCdgM2qhazalbcJ6zDKHCZWVWm\n8RRxDGldyMb/237JxETzP40tAlzOZDmBAbUgEnurDJ93RVDIE3rbZUshwgeQd18a\nem096mWgvB1AIKYgsTAR3pw+V19YWAjq/glP6fz8wQKBgQD/oQq+ukKF0PRgBeM5\ngeTjSwsdGppQLmf5ndujvoiz/TpdjDEPu6R8kigQr1rG2t4K/yfdZoI8RdmJD1al\n3Q7N9hofooSy4rj6E3txzWZCHJjHad2cnCp/O26HiReGAl7wTcfTmNdiFHhZQzm5\nJBkvWAiwuvQMNfEbnXxw6/vIDwKBgQDH7fX8gsc77JLvAWgp1MaQN/sbqVb6JeT1\nFQfR8E/WFCSmzQBtNzd5KgYuCeelwr/8DyYytvN2BzCYZXp73gI1jF3YlW5jVn74\nOY6TwQ095digwo6Z0yuxopdIOApKgAkL9PRKgNrqAf3NAyMua6lOGifzjDojC3KU\nfylQmxMn4wKBgHp2B9O/H0dEBw5JQ8W0+JX6yWQz7mEjGiR2/1W+XXb8hQ1zr709\nw1r6Gb+EghRpnZ3fBpYGGbYOMFx8wKHM+N6qW3F0ReX8v2juFGE8aRSa5oYBrWzt\nU16Idjbv8hj84cZ1PJmdyvDtpYn9rpWHOZl4rxEbPvbqkIsOMyNVqdT5AoGAOSge\nmwIIU2le2FVeohbibXiToWTYKMuMmURZ5/r72AgKMmWJKbAPe+Q3wBG01/7FRBpQ\noU8Ma0HC8s6QJbliiEyIx9JwrJWd1vkdecBHONrtA4ibm/5zD2WcOllLF+FitLhi\n3qnX6+6F0IaFGFBPJrTzlv0P4dTz/OAdv52V7GECgYEA2TttOKBAqWllgOaZOkql\nLVMJVmgR7s6tLi1+cEP8ZcapV9aRbRzTAKXm4f8AEhtlG9F9kCOvHYCYGi6JaiWJ\nZkHjeex3T+eE6Di6y5Bm/Ift5jtVhJ4jCVwHOKTMej79NPUFTJfv8hCo29haBDv6\nRXFrv+T21KCcw8k3sJeJWWQ=\n-----END PRIVATE KEY-----";
30052
30225
  /*
30053
30226
  * The crypto algorithm used for importing key and signing string
30054
30227
  */
@@ -32597,7 +32770,38 @@ const getAllBlockedUsers = async () => {
32597
32770
  const engine = BlockedUserSyncEngine$1.getInstance();
32598
32771
  // Ensure data is fetched (no-op if cache is fresh)
32599
32772
  await engine.ensureFetched();
32600
- // Read from the engine's bounded ID list — O(blocked users) not O(cache size)
32773
+ return engine.getCachedUsers();
32774
+ };
32775
+ /* end_public_function */
32776
+
32777
+ /* begin_public_function
32778
+ id: user.get_all_blocking_users
32779
+ */
32780
+ /**
32781
+ * ```js
32782
+ * import { UserRepository } from '@amityco/ts-sdk'
32783
+ * const blockingUsers = await UserRepository.getAllBlockingUsers()
32784
+ * ```
32785
+ *
32786
+ * Returns all users who have blocked the current user
32787
+ * non-paginated list (limit 100) with TTL-based caching (5-minute window). Within the
32788
+ * TTL window, subsequent calls resolve instantly from the local store without any
32789
+ * server call. After the TTL expires, the next call triggers a fresh server fetch.
32790
+ *
32791
+ * The directional inverse of {@link getAllBlockedUsers}.
32792
+ *
32793
+ * @returns A promise that resolves to an array of blocking {@link Amity.User} objects
32794
+ *
32795
+ * @category Block API
32796
+ * @async
32797
+ */
32798
+ const getAllBlockingUsers = async () => {
32799
+ const client = getActiveClient();
32800
+ client.log('user/getAllBlockingUsers');
32801
+ const engine = BlockingUserSyncEngine$1.getInstance();
32802
+ // Ensure data is fetched (no-op if cache is fresh)
32803
+ await engine.ensureFetched();
32804
+ // Read from the engine's bounded ID list — O(blocking users) not O(cache size)
32601
32805
  return engine.getCachedUsers();
32602
32806
  };
32603
32807
  /* end_public_function */
@@ -33176,14 +33380,6 @@ const getBlockedUsers = (params, callback, config) => {
33176
33380
  };
33177
33381
  /* end_public_function */
33178
33382
 
33179
- function prepareBlockingUserPayload(response) {
33180
- const { users, follows } = response, rest = __rest(response, ["users", "follows"]);
33181
- return Object.assign(Object.assign({}, rest), { follows: follows.map(follow => {
33182
- const followUser = users.find(user => user.userId === follow.from);
33183
- return Object.assign(Object.assign({}, follow), { user: convertRawUserToInternalUser(followUser) });
33184
- }), users: users.map(convertRawUserToInternalUser) });
33185
- }
33186
-
33187
33383
  class BlockingUserQueryStreamController extends QueryStreamController {
33188
33384
  constructor(query, cacheKey, notifyChange, preparePayload) {
33189
33385
  super(query, cacheKey);
@@ -33628,6 +33824,7 @@ var index$q = /*#__PURE__*/Object.freeze({
33628
33824
  unflagUser: unflagUser,
33629
33825
  isUserFlaggedByMe: isUserFlaggedByMe,
33630
33826
  getAllBlockedUsers: getAllBlockedUsers,
33827
+ getAllBlockingUsers: getAllBlockingUsers,
33631
33828
  onUserUpdated: onUserUpdated,
33632
33829
  onUserDeleted: onUserDeleted$2,
33633
33830
  onUserFlagged: onUserFlagged,
@@ -39737,6 +39934,405 @@ const getArchivedChannels = (params, callback) => {
39737
39934
  };
39738
39935
  /* end_public_function */
39739
39936
 
39937
+ class SearchChannelPaginationController extends PaginationController {
39938
+ async getRequest(queryParams, token) {
39939
+ const { query, exactMatch, isMemberOnly, types, tags, sortBy, orderBy, limit = COLLECTION_DEFAULT_PAGINATION_SIZE, } = queryParams;
39940
+ const options = token ? { token } : { limit: Math.min(100, Math.max(1, limit)) };
39941
+ const { data: queryResponse } = await this.http.get(`/api/v2/search/channels`, {
39942
+ params: {
39943
+ query,
39944
+ exactMatch,
39945
+ isMemberOnly,
39946
+ types,
39947
+ tags,
39948
+ sortBy,
39949
+ orderBy,
39950
+ options,
39951
+ },
39952
+ });
39953
+ return queryResponse;
39954
+ }
39955
+ }
39956
+
39957
+ class SearchChannelQueryStreamController extends QueryStreamController {
39958
+ constructor(query, cacheKey, notifyChange) {
39959
+ super(query, cacheKey);
39960
+ this.notifyChange = notifyChange;
39961
+ }
39962
+ async saveToMainDB(response) {
39963
+ const processedPayload = await prepareChannelPayload(response);
39964
+ const client = getActiveClient();
39965
+ const cachedAt = client.cache && Date.now();
39966
+ if (client.cache) {
39967
+ ingestInCache(processedPayload, { cachedAt });
39968
+ }
39969
+ }
39970
+ appendToQueryStream(response, direction, refresh = false) {
39971
+ var _a, _b;
39972
+ if (refresh) {
39973
+ pushToCache(this.cacheKey, {
39974
+ data: response.channels.map(getResolver('channel')),
39975
+ });
39976
+ return;
39977
+ }
39978
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
39979
+ const existing = (_b = collection === null || collection === void 0 ? void 0 : collection.data) !== null && _b !== void 0 ? _b : [];
39980
+ const incoming = response.channels.map(getResolver('channel'));
39981
+ pushToCache(this.cacheKey, Object.assign(Object.assign({}, collection), { data: direction === "prev" /* Amity.LiveCollectionPageDirection.PREV */
39982
+ ? [...new Set([...incoming, ...existing])]
39983
+ : [...new Set([...existing, ...incoming])] }));
39984
+ }
39985
+ reactor() {
39986
+ return () => this.notifyChange({ origin: "event" /* Amity.LiveDataOrigin.EVENT */, loading: false });
39987
+ }
39988
+ subscribeRTE(createSubscriber) {
39989
+ return createSubscriber.map(subscriber => subscriber.fn(this.reactor()));
39990
+ }
39991
+ }
39992
+
39993
+ /* eslint-disable no-use-before-define */
39994
+ const getMessagePreviewSetting = () => {
39995
+ const client = getActiveClient();
39996
+ return client.getMessagePreviewSetting(false);
39997
+ };
39998
+ class SearchChannelLiveCollectionController extends LiveCollectionController {
39999
+ constructor(query, callback) {
40000
+ const queryStreamId = hash(query);
40001
+ const cacheKey = ['channel', 'search', queryStreamId];
40002
+ const paginationController = new SearchChannelPaginationController(query);
40003
+ super(paginationController, queryStreamId, cacheKey, callback);
40004
+ this.queryStreamController = new SearchChannelQueryStreamController(query, this.cacheKey, this.notifyChange.bind(this));
40005
+ this.callback = callback.bind(this);
40006
+ this.loadPage({ initial: true });
40007
+ }
40008
+ startSubscription() {
40009
+ return this.queryStreamController.subscribeRTE(this.getSubscriptions());
40010
+ }
40011
+ notifyChange({ origin, loading, error }) {
40012
+ var _a, _b;
40013
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
40014
+ if (!collection)
40015
+ return;
40016
+ const data = (_b = collection.data
40017
+ .map(channelId => pullFromCache(['channel', 'get', channelId]))
40018
+ .filter(Boolean)
40019
+ .map(cached => constructChannelObject(cached.data))) !== null && _b !== void 0 ? _b : [];
40020
+ if (!this.shouldNotify(data) && origin === 'event')
40021
+ return;
40022
+ this.callback({
40023
+ onNextPage: () => this.loadPage({ direction: "next" /* Amity.LiveCollectionPageDirection.NEXT */ }),
40024
+ data,
40025
+ hasNextPage: !!this.paginationController.getNextToken(),
40026
+ loading,
40027
+ error,
40028
+ });
40029
+ }
40030
+ setup() {
40031
+ var _a;
40032
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
40033
+ if (!collection) {
40034
+ pushToCache(this.cacheKey, {
40035
+ data: [],
40036
+ params: {},
40037
+ });
40038
+ }
40039
+ }
40040
+ async persistModel(response) {
40041
+ await this.queryStreamController.saveToMainDB(response);
40042
+ }
40043
+ persistQueryStream({ response, direction, refresh, }) {
40044
+ this.queryStreamController.appendToQueryStream(response, direction, refresh);
40045
+ }
40046
+ shouldAbort(targetChannelId) {
40047
+ var _a;
40048
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
40049
+ if (!collection)
40050
+ return true;
40051
+ return !collection.data.find(channelId => channelId === targetChannelId);
40052
+ }
40053
+ getSubscriptions() {
40054
+ return [
40055
+ {
40056
+ fn: convertEventPayload((callback) => {
40057
+ return onMessageCreatedMqtt(message => {
40058
+ var _a;
40059
+ const cacheData = (_a = pullFromCache([
40060
+ 'channel',
40061
+ 'get',
40062
+ message.channelId,
40063
+ ])) === null || _a === void 0 ? void 0 : _a.data;
40064
+ if (!cacheData)
40065
+ return;
40066
+ updateChannelCache(cacheData, {
40067
+ lastActivity: message.createdAt,
40068
+ });
40069
+ callback(message);
40070
+ });
40071
+ }, 'channelId', 'channel'),
40072
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40073
+ },
40074
+ {
40075
+ fn: convertEventPayload((callback) => {
40076
+ return onMessageCreatedLocal(message => {
40077
+ var _a;
40078
+ const cacheData = (_a = pullFromCache([
40079
+ 'channel',
40080
+ 'get',
40081
+ message.channelId,
40082
+ ])) === null || _a === void 0 ? void 0 : _a.data;
40083
+ if (!cacheData)
40084
+ return;
40085
+ updateChannelCache(cacheData, {
40086
+ lastActivity: message.createdAt,
40087
+ });
40088
+ callback(message);
40089
+ });
40090
+ }, 'channelId', 'channel'),
40091
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40092
+ },
40093
+ { fn: onChannelDeleted, action: "onDelete" /* Amity.ChannelActionType.OnDelete */ },
40094
+ { fn: onChannelUpdated, action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */ },
40095
+ { fn: onChannelSetMuted, action: "onMute" /* Amity.ChannelActionType.OnMute */ },
40096
+ {
40097
+ fn: (reactor) => onChannelArchived(payload => {
40098
+ const channels = payload.archives
40099
+ .map(archive => {
40100
+ var _a;
40101
+ return (_a = pullFromCache(['channel', 'get', archive.channelId])) === null || _a === void 0 ? void 0 : _a.data;
40102
+ })
40103
+ .filter((c) => Boolean(c));
40104
+ if (channels.length > 0)
40105
+ reactor(channels);
40106
+ }),
40107
+ action: "onArchived" /* Amity.ChannelActionType.OnArchived */,
40108
+ },
40109
+ {
40110
+ fn: (reactor) => onChannelUnarchived(payload => {
40111
+ const channels = payload.archives
40112
+ .map(archive => {
40113
+ var _a;
40114
+ return (_a = pullFromCache(['channel', 'get', archive.channelId])) === null || _a === void 0 ? void 0 : _a.data;
40115
+ })
40116
+ .filter((c) => Boolean(c));
40117
+ if (channels.length > 0)
40118
+ reactor(channels);
40119
+ }),
40120
+ action: "onUnarchived" /* Amity.ChannelActionType.OnUnarchived */,
40121
+ },
40122
+ {
40123
+ fn: convertEventPayload(onChannelMarkerFetched, 'entityId', 'channel'),
40124
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40125
+ },
40126
+ {
40127
+ fn: convertEventPayload(onChannelMarkerUpdated, 'entityId', 'channel'),
40128
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40129
+ },
40130
+ {
40131
+ fn: convertEventPayload((callback) => {
40132
+ const updateMessagePreview = async (message) => {
40133
+ var _a;
40134
+ const messagePreviewSetting = await getMessagePreviewSetting();
40135
+ if (messagePreviewSetting === "no-message-preview" /* Amity.MessagePreviewSetting.NO_MESSAGE_PREVIEW */)
40136
+ return;
40137
+ handleMessageCreated(message);
40138
+ if (this.shouldAbort(message.channelId))
40139
+ return;
40140
+ const channel = (_a = pullFromCache([
40141
+ 'channel',
40142
+ 'get',
40143
+ message.channelId,
40144
+ ])) === null || _a === void 0 ? void 0 : _a.data;
40145
+ if (!channel)
40146
+ return;
40147
+ updateChannelCache(channel, {
40148
+ messagePreviewId: message.messageId,
40149
+ });
40150
+ callback(message);
40151
+ };
40152
+ return onMessageCreatedMqtt(updateMessagePreview);
40153
+ }, 'channelId', 'channel'),
40154
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40155
+ },
40156
+ {
40157
+ fn: convertEventPayload((callback) => {
40158
+ const updateMessagePreview = async (message) => {
40159
+ var _a;
40160
+ const messagePreviewSetting = await getMessagePreviewSetting();
40161
+ if (messagePreviewSetting === "no-message-preview" /* Amity.MessagePreviewSetting.NO_MESSAGE_PREVIEW */)
40162
+ return;
40163
+ handleMessageCreated(message);
40164
+ if (this.shouldAbort(message.channelId))
40165
+ return;
40166
+ const channel = (_a = pullFromCache([
40167
+ 'channel',
40168
+ 'get',
40169
+ message.channelId,
40170
+ ])) === null || _a === void 0 ? void 0 : _a.data;
40171
+ if (!channel)
40172
+ return;
40173
+ updateChannelCache(channel, {
40174
+ messagePreviewId: message.messageId,
40175
+ });
40176
+ callback(message);
40177
+ };
40178
+ return onMessageCreatedLocal(updateMessagePreview);
40179
+ }, 'channelId', 'channel'),
40180
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40181
+ },
40182
+ {
40183
+ fn: convertEventPayload((callback) => {
40184
+ const updateMessagePreview = async (message) => {
40185
+ const messagePreviewSetting = await getMessagePreviewSetting();
40186
+ if (messagePreviewSetting === "no-message-preview" /* Amity.MessagePreviewSetting.NO_MESSAGE_PREVIEW */)
40187
+ return;
40188
+ handleMessageUpdated(message);
40189
+ if (this.shouldAbort(message.channelId))
40190
+ return;
40191
+ callback(message);
40192
+ };
40193
+ return onMessageUpdated(updateMessagePreview);
40194
+ }, 'channelId', 'channel'),
40195
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40196
+ },
40197
+ {
40198
+ fn: convertEventPayload((callback) => {
40199
+ const updateMessagePreview = async (message) => {
40200
+ const messagePreviewSetting = await getMessagePreviewSetting();
40201
+ if (messagePreviewSetting === "no-message-preview" /* Amity.MessagePreviewSetting.NO_MESSAGE_PREVIEW */)
40202
+ return;
40203
+ if (messagePreviewSetting ===
40204
+ "message-preview-include-deleted" /* Amity.MessagePreviewSetting.MESSAGE_PREVIEW_INCLUDE_DELETED */)
40205
+ await handleMessageUpdated(message);
40206
+ if (this.shouldAbort(message.channelId))
40207
+ return;
40208
+ if (messagePreviewSetting ===
40209
+ "message-preview-not-include-deleted" /* Amity.MessagePreviewSetting.MESSAGE_PREVIEW_NOT_INCLUDE_DELETED */) {
40210
+ await getChannel$1(message.channelId);
40211
+ }
40212
+ callback(message);
40213
+ };
40214
+ return onMessageDeleted(updateMessagePreview);
40215
+ }, 'channelId', 'channel'),
40216
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40217
+ },
40218
+ {
40219
+ fn: convertEventPayload((callback) => {
40220
+ const updateMessagePreview = async (subChannel) => {
40221
+ var _a;
40222
+ const collections = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
40223
+ if (!collections)
40224
+ return;
40225
+ const channelId = collections.data.find(channel => {
40226
+ const messagePreviewCache = getChannelMessagePreview(channel);
40227
+ return (messagePreviewCache === null || messagePreviewCache === void 0 ? void 0 : messagePreviewCache.subChannelId) === subChannel.subChannelId;
40228
+ });
40229
+ if (!channelId)
40230
+ return;
40231
+ await getChannel$1(subChannel.channelId);
40232
+ callback(subChannel);
40233
+ };
40234
+ return onSubChannelDeleted(updateMessagePreview);
40235
+ }, 'channelId', 'channel'),
40236
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40237
+ },
40238
+ {
40239
+ fn: convertEventPayload((callback) => {
40240
+ const updateMessagePreview = async (subChannel) => {
40241
+ var _a;
40242
+ const messagePreviewSetting = await getMessagePreviewSetting();
40243
+ if (messagePreviewSetting === "no-message-preview" /* Amity.MessagePreviewSetting.NO_MESSAGE_PREVIEW */)
40244
+ return;
40245
+ const collections = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
40246
+ if (!collections)
40247
+ return;
40248
+ await handleSubChannelUpdated(subChannel);
40249
+ if (this.shouldAbort(subChannel.channelId))
40250
+ return;
40251
+ callback(subChannel);
40252
+ };
40253
+ return onSubChannelUpdated(updateMessagePreview);
40254
+ }, 'channelId', 'channel'),
40255
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40256
+ },
40257
+ {
40258
+ fn: (callback) => {
40259
+ const handleUserFeedMarkerResolved = async (marker) => {
40260
+ if (marker.feedMarkers) {
40261
+ const channels = marker.feedMarkers
40262
+ .map(feedMarker => {
40263
+ var _a;
40264
+ return (_a = pullFromCache([
40265
+ 'channel',
40266
+ 'get',
40267
+ feedMarker.entityId,
40268
+ ])) === null || _a === void 0 ? void 0 : _a.data;
40269
+ })
40270
+ .filter(Boolean);
40271
+ callback(channels);
40272
+ }
40273
+ };
40274
+ return onUserMessageFeedMarkerResolved(handleUserFeedMarkerResolved);
40275
+ },
40276
+ action: "OnResolveUnread" /* Amity.ChannelActionType.OnResolveUnread */,
40277
+ },
40278
+ {
40279
+ fn: convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
40280
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40281
+ },
40282
+ {
40283
+ fn: convertEventPayload((callback) => {
40284
+ const processPayload = (payloads) => {
40285
+ payloads.forEach(callback);
40286
+ };
40287
+ return onChannelUnreadUpdatedLocal(processPayload);
40288
+ }, 'channelId', 'channel'),
40289
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
40290
+ },
40291
+ ];
40292
+ }
40293
+ }
40294
+
40295
+ /* begin_public_function
40296
+ id: channel.search
40297
+ */
40298
+ /**
40299
+ * ```js
40300
+ * import { ChannelRepository } from '@amityco/ts-sdk';
40301
+ *
40302
+ * const unsubscribe = ChannelRepository.searchChannels(
40303
+ * { query: 'hello' },
40304
+ * response => response.data,
40305
+ * );
40306
+ * ```
40307
+ *
40308
+ * Live collection of {@link Amity.Channel}s matching the search query. Backed by
40309
+ * `GET /api/v2/search/channels`.
40310
+ *
40311
+ * @param params Search parameters.
40312
+ * @param callback Called whenever new data are available.
40313
+ * @returns An {@link Amity.Unsubscriber} function to stop observing.
40314
+ *
40315
+ * @category Channel Live Collection
40316
+ */
40317
+ const searchChannels = (params, callback) => {
40318
+ const { log, cache } = getActiveClient();
40319
+ if (!cache)
40320
+ console.log(ENABLE_CACHE_MESSAGE);
40321
+ const timestamp = Date.now();
40322
+ log(`searchChannels(tmpid: ${timestamp}) > listen`);
40323
+ const searchChannelLiveCollection = new SearchChannelLiveCollectionController(params, callback);
40324
+ const disposers = searchChannelLiveCollection.startSubscription();
40325
+ const cacheKey = searchChannelLiveCollection.getCacheKey();
40326
+ disposers.push(() => {
40327
+ dropFromCache(cacheKey);
40328
+ });
40329
+ return () => {
40330
+ log(`searchChannels(tmpid: ${timestamp}) > dispose`);
40331
+ disposers.forEach(fn => fn());
40332
+ };
40333
+ };
40334
+ /* end_public_function */
40335
+
39740
40336
  /* begin_public_function
39741
40337
  id: channel.member.add
39742
40338
  */
@@ -40370,6 +40966,7 @@ var index$j = /*#__PURE__*/Object.freeze({
40370
40966
  getChannels: getChannels,
40371
40967
  getTotalChannelsUnread: getTotalChannelsUnread,
40372
40968
  getArchivedChannels: getArchivedChannels,
40969
+ searchChannels: searchChannels,
40373
40970
  MARKER_INCLUDED_CHANNEL_TYPE: MARKER_INCLUDED_CHANNEL_TYPE,
40374
40971
  isUnreadCountSupport: isUnreadCountSupport,
40375
40972
  convertFromRaw: convertFromRaw,
@@ -45441,45 +46038,80 @@ class ForYouFeedPaginationController extends PaginationController {
45441
46038
  constructor(query) {
45442
46039
  super(query);
45443
46040
  this.checkedDisk = false;
46041
+ this.hasDeliveredPost = false;
45444
46042
  this.cursor = CursorController.current();
45445
46043
  }
45446
46044
  async getRequest(_queryParams, token) {
45447
- let effectiveToken = token;
45448
- if (!effectiveToken && !this.checkedDisk && this.cursor) {
46045
+ var _a, _b, _c, _d, _e;
46046
+ const isFirstPage = token === undefined;
46047
+ let stored = null;
46048
+ // On the first page of a fresh collection, load the saved cursor from disk once.
46049
+ // Drop it if the snapshot has already expired so we start fresh.
46050
+ if (isFirstPage && !this.checkedDisk && this.cursor) {
45449
46051
  this.checkedDisk = true;
45450
- const stored = await this.cursor.get();
45451
- if (stored && !CursorController.isExpired(stored.expiredAt)) {
45452
- effectiveToken = stored.cursor;
45453
- }
45454
- else if (stored) {
46052
+ stored = await this.cursor.get();
46053
+ if (stored && CursorController.isExpired(stored.expiredAt)) {
45455
46054
  await this.cursor.clear();
46055
+ stored = null;
45456
46056
  }
45457
46057
  }
45458
- const options = {
45459
- limit: COLLECTION_DEFAULT_PAGINATION_SIZE,
45460
- };
45461
- if (effectiveToken)
45462
- options.token = effectiveToken;
45463
- let queryResponse;
46058
+ // Already paged to the end before. Ask the BE fresh (no cursor) and check if it's
46059
+ // still the same snapshot the user finished.
46060
+ if (isFirstPage && (stored === null || stored === void 0 ? void 0 : stored.reachedEndOfFeed)) {
46061
+ const fresh = await this.fetch();
46062
+ const freshExpiredAt = Date.parse((_b = (_a = fresh.paging) === null || _a === void 0 ? void 0 : _a.expiredAt) !== null && _b !== void 0 ? _b : '');
46063
+ const rolledOver = !Number.isNaN(freshExpiredAt) && freshExpiredAt !== stored.expiredAt;
46064
+ // New snapshot → serve it. Same snapshot → user has seen it all, show empty.
46065
+ if (rolledOver) {
46066
+ await this.persistCursor(fresh);
46067
+ if (fresh.posts.length > 0)
46068
+ this.hasDeliveredPost = true;
46069
+ return fresh;
46070
+ }
46071
+ return Object.assign(Object.assign({}, fresh), { posts: [], paging: {} });
46072
+ }
46073
+ // Resume from the saved cursor on re-entry; otherwise use the live-collection token.
46074
+ const effectiveToken = isFirstPage && stored ? stored.cursor : token;
46075
+ const response = await this.fetch(effectiveToken);
46076
+ if (response.posts.length > 0)
46077
+ this.hasDeliveredPost = true;
46078
+ if ((_c = response.paging) === null || _c === void 0 ? void 0 : _c.next) {
46079
+ // More pages left → advance the saved cursor.
46080
+ await this.persistCursor(response);
46081
+ }
46082
+ else if (this.hasDeliveredPost && this.cursor) {
46083
+ // Reached the end and mark end of feed
46084
+ const expiredAt = Date.parse((_e = (_d = response.paging) === null || _d === void 0 ? void 0 : _d.expiredAt) !== null && _e !== void 0 ? _e : '');
46085
+ if (!Number.isNaN(expiredAt))
46086
+ await this.cursor.markReachedEndOfFeed(expiredAt);
46087
+ }
46088
+ return response;
46089
+ }
46090
+ async fetch(token) {
46091
+ const options = { limit: COLLECTION_DEFAULT_PAGINATION_SIZE };
46092
+ if (token)
46093
+ options.token = token;
45464
46094
  try {
45465
- ({ data: queryResponse } = await this.http.get(API_ENDPOINTS.forYouFeed, { params: { options } }));
46095
+ const { data } = await this.http.get(API_ENDPOINTS.forYouFeed, {
46096
+ params: { options },
46097
+ });
46098
+ return data;
45466
46099
  }
45467
46100
  catch (error) {
45468
46101
  if (error instanceof ASCApiError && error.code === 400300 /* Amity.ServerError.FORBIDDEN */) {
45469
46102
  throw new AmityForYouFeedDisabledError();
45470
46103
  }
45471
46104
  const recoverable = error instanceof ASCApiError && error.code === 400322 /* Amity.ServerError.FEED_SNAPSHOT_EXPIRED */;
45472
- if (recoverable && effectiveToken !== undefined) {
46105
+ if (recoverable && token !== undefined) {
45473
46106
  if (this.cursor)
45474
46107
  await this.cursor.clear();
45475
- ({ data: queryResponse } = await this.http.get(API_ENDPOINTS.forYouFeed, { params: { options: { limit: COLLECTION_DEFAULT_PAGINATION_SIZE } } }));
45476
- }
45477
- else {
45478
- throw error;
46108
+ const { data } = await this.http.get(API_ENDPOINTS.forYouFeed, {
46109
+ params: { options: { limit: COLLECTION_DEFAULT_PAGINATION_SIZE } },
46110
+ });
46111
+ return data;
45479
46112
  }
46113
+ throw error;
45480
46114
  }
45481
- await this.persistCursor(queryResponse);
45482
- return queryResponse;
45483
46115
  }
45484
46116
  async persistCursor(response) {
45485
46117
  var _a, _b;