@amityco/ts-sdk-react-native 7.26.1-fbe5a6dd.0 → 7.27.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 (59) hide show
  1. package/dist/@types/core/transport.d.ts +3 -3
  2. package/dist/@types/core/transport.d.ts.map +1 -1
  3. package/dist/@types/domains/client.d.ts +9 -0
  4. package/dist/@types/domains/client.d.ts.map +1 -1
  5. package/dist/@types/domains/content.d.ts +6 -1
  6. package/dist/@types/domains/content.d.ts.map +1 -1
  7. package/dist/@types/domains/file.d.ts +11 -2
  8. package/dist/@types/domains/file.d.ts.map +1 -1
  9. package/dist/@types/domains/liveViewerCount.d.ts +22 -0
  10. package/dist/@types/domains/liveViewerCount.d.ts.map +1 -0
  11. package/dist/@types/index.d.ts +1 -0
  12. package/dist/@types/index.d.ts.map +1 -1
  13. package/dist/client/api/createClient.d.ts.map +1 -1
  14. package/dist/client/api/getLiveViewerCountConfig.d.ts +24 -0
  15. package/dist/client/api/getLiveViewerCountConfig.d.ts.map +1 -0
  16. package/dist/client/api/index.d.ts +1 -0
  17. package/dist/client/api/index.d.ts.map +1 -1
  18. package/dist/client/api/loginWithAccessToken.d.ts.map +1 -1
  19. package/dist/client/api/logout.d.ts.map +1 -1
  20. package/dist/client/api/renewTokenWithHandler.d.ts.map +1 -1
  21. package/dist/client/api/renewWithAccessToken.d.ts.map +1 -1
  22. package/dist/client/api/resumeSession.d.ts.map +1 -1
  23. package/dist/client/api/tests/renewTokenWithHandler.test.d.ts +2 -0
  24. package/dist/client/api/tests/renewTokenWithHandler.test.d.ts.map +1 -0
  25. package/dist/client/api/tests/renewWithAccessToken.test.d.ts +2 -0
  26. package/dist/client/api/tests/renewWithAccessToken.test.d.ts.map +1 -0
  27. package/dist/client/api/tests/validateAccessToken.test.d.ts +2 -0
  28. package/dist/client/api/tests/validateAccessToken.test.d.ts.map +1 -0
  29. package/dist/client/api/validateAccessToken.d.ts +1 -1
  30. package/dist/client/api/validateAccessToken.d.ts.map +1 -1
  31. package/dist/core/transports/mqtt.d.ts.map +1 -1
  32. package/dist/fileRepository/api/getFile.d.ts.map +1 -1
  33. package/dist/fileRepository/api/uploadImage.d.ts.map +1 -1
  34. package/dist/fileRepository/api/uploadVideo.d.ts.map +1 -1
  35. package/dist/index.cjs.js +221 -117
  36. package/dist/index.esm.js +222 -118
  37. package/dist/index.umd.js +1 -1
  38. package/dist/postRepository/events/utils.d.ts.map +1 -1
  39. package/dist/userRepository/observers/index.d.ts +1 -0
  40. package/dist/userRepository/observers/index.d.ts.map +1 -1
  41. package/dist/userRepository/observers/searchUserByDisplayName.d.ts +2 -0
  42. package/dist/userRepository/observers/searchUserByDisplayName.d.ts.map +1 -1
  43. package/dist/userRepository/observers/searchUsers.d.ts +26 -0
  44. package/dist/userRepository/observers/searchUsers.d.ts.map +1 -0
  45. package/dist/userRepository/observers/tests/integrations/searchUsers.integration.test.d.ts +2 -0
  46. package/dist/userRepository/observers/tests/integrations/searchUsers.integration.test.d.ts.map +1 -0
  47. package/dist/userRepository/observers/tests/searchUsers.test.d.ts +2 -0
  48. package/dist/userRepository/observers/tests/searchUsers.test.d.ts.map +1 -0
  49. package/dist/utils/linkedObject/fileLinkedObject.d.ts +2 -0
  50. package/dist/utils/linkedObject/fileLinkedObject.d.ts.map +1 -0
  51. package/dist/utils/linkedObject/index.d.ts +1 -0
  52. package/dist/utils/linkedObject/index.d.ts.map +1 -1
  53. package/dist/utils/linkedObject/postLinkedObject.d.ts.map +1 -1
  54. package/dist/utils/tests/dummy/file.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/dist/postRepository/events/parentPost.d.ts +0 -32
  57. package/dist/postRepository/events/parentPost.d.ts.map +0 -1
  58. package/dist/postRepository/events/tests/parentPost.test.d.ts +0 -2
  59. package/dist/postRepository/events/tests/parentPost.test.d.ts.map +0 -1
package/dist/index.cjs.js CHANGED
@@ -343,10 +343,17 @@ exports.NotificationRolesFilterTypeEnum = void 0;
343
343
  NotificationRolesFilterTypeEnum["ONLY"] = "only";
344
344
  })(exports.NotificationRolesFilterTypeEnum || (exports.NotificationRolesFilterTypeEnum = {}));
345
345
 
346
+ exports.AmityLiveViewerCountMode = void 0;
347
+ (function (AmityLiveViewerCountMode) {
348
+ AmityLiveViewerCountMode["ALWAYS_SHOW"] = "always";
349
+ AmityLiveViewerCountMode["HIDE_ENTIRELY"] = "hidden";
350
+ AmityLiveViewerCountMode["SHOW_ABOVE_MINIMUM"] = "above-minimum";
351
+ })(exports.AmityLiveViewerCountMode || (exports.AmityLiveViewerCountMode = {}));
352
+
346
353
  function getVersion() {
347
354
  try {
348
- // the string ''v7.26.0-cjs'' should be replaced by actual value by @rollup/plugin-replace
349
- return 'v7.26.0-cjs';
355
+ // the string ''v7.27.0-cjs'' should be replaced by actual value by @rollup/plugin-replace
356
+ return 'v7.27.0-cjs';
350
357
  }
351
358
  catch (error) {
352
359
  return '__dev__';
@@ -2496,10 +2503,11 @@ var MqttError;
2496
2503
  MqttError[MqttError["BAD_USERNAME_OR_PASSWORD"] = 134] = "BAD_USERNAME_OR_PASSWORD";
2497
2504
  MqttError[MqttError["NOT_AUTHORIZED"] = 135] = "NOT_AUTHORIZED";
2498
2505
  })(MqttError || (MqttError = {}));
2499
- // MQTT 5 session expiry, in seconds. 0xFFFFFFFF keeps the session alive
2500
- // indefinitely, matching the previous 3.1.1 `clean: false` behaviour where the
2501
- // broker retained the session (and its subscriptions) across disconnects.
2502
- const SESSION_EXPIRY_INTERVAL = 0xffffffff;
2506
+ // MQTT 5 session expiry, in seconds. Under MQTT 3.1.1 the broker capped
2507
+ // retained sessions at ~30 min; under MQTT 5 the client's value wins, so an
2508
+ // unbounded value ("never") left disconnected sessions piling up on the broker.
2509
+ // 1800s matches the previous 3.1.1 cap.
2510
+ const SESSION_EXPIRY_INTERVAL = 1800;
2503
2511
  function getMqttOptions(params) {
2504
2512
  return Object.assign({ clean: false, clientId: `mqttjs_ + ${Math.random().toString(16).substring(2, 10)}`, protocolId: 'MQTT', protocolVersion: 5, reconnectPeriod: RETRY_BASE_TIMEOUT, resubscribe: true,
2505
2513
  // The broker/LB drops idle sockets at ~60s. mqtt.js v5 sends its first
@@ -2616,8 +2624,16 @@ const createMqttTransport = (endpoint) => {
2616
2624
  }
2617
2625
  return {
2618
2626
  connect,
2619
- async disconnect() {
2627
+ async disconnect(options) {
2620
2628
  if (this.connected) {
2629
+ // On logout we want the broker to release the session immediately
2630
+ // instead of keeping it around for SESSION_EXPIRY_INTERVAL. mqtt.js
2631
+ // only sends a DISCONNECT packet when `force` is false; force=true
2632
+ // just tears the socket down and the broker keeps the session until
2633
+ // it expires on its own.
2634
+ if (options === null || options === void 0 ? void 0 : options.endSession) {
2635
+ return new Promise(resolve => mqttClient === null || mqttClient === void 0 ? void 0 : mqttClient.end(false, { reasonCode: 0, properties: { sessionExpiryInterval: 0 } }, () => resolve()));
2636
+ }
2621
2637
  return new Promise(resolve => mqttClient === null || mqttClient === void 0 ? void 0 : mqttClient.end(true, undefined, () => resolve()));
2622
2638
  }
2623
2639
  },
@@ -5097,6 +5113,51 @@ const getCoreUserSettings = async () => {
5097
5113
  return data;
5098
5114
  };
5099
5115
 
5116
+ const DEFAULT_CONFIG = {
5117
+ mode: exports.AmityLiveViewerCountMode.ALWAYS_SHOW,
5118
+ threshold: 50,
5119
+ };
5120
+ const isValidMode = (value) => value === exports.AmityLiveViewerCountMode.ALWAYS_SHOW ||
5121
+ value === exports.AmityLiveViewerCountMode.HIDE_ENTIRELY ||
5122
+ value === exports.AmityLiveViewerCountMode.SHOW_ABOVE_MINIMUM;
5123
+ const isValidThreshold = (value) => typeof value === 'number' && Number.isInteger(value) && value >= 1 && value <= 1000;
5124
+ /**
5125
+ * ```js
5126
+ * import { getLiveViewerCountConfig } from '@amityco/ts-sdk'
5127
+ * const config = await getLiveViewerCountConfig()
5128
+ * ```
5129
+ *
5130
+ * Fetches the network-level {@link Amity.LiveViewerCountConfig} governing
5131
+ * how the live viewer count is displayed to viewers on a livestream.
5132
+ *
5133
+ * Cold-read — no observable, no cache. Call once per livestream mount /
5134
+ * rejoin. Admin-driven config changes take effect on the next join, not
5135
+ * mid-stream.
5136
+ *
5137
+ * On a malformed payload (unknown mode, out-of-range or missing threshold)
5138
+ * the SDK falls open to `{ mode: ALWAYS_SHOW, threshold: 50 }` and logs a
5139
+ * warning. Network errors reject.
5140
+ *
5141
+ * @returns A Promise of {@link Amity.LiveViewerCountConfig}
5142
+ *
5143
+ * @category Client API
5144
+ * @async
5145
+ */
5146
+ /* begin_public_function id: client.getLiveViewerCountConfig */
5147
+ const getLiveViewerCountConfig = async () => {
5148
+ var _a, _b;
5149
+ const client = getActiveClient();
5150
+ const { data } = await client.http.get('/api/v3/network-settings/video-streaming');
5151
+ const mode = (_a = data === null || data === void 0 ? void 0 : data.videoStreaming) === null || _a === void 0 ? void 0 : _a.viewerCountDisplayMode;
5152
+ const threshold = (_b = data === null || data === void 0 ? void 0 : data.videoStreaming) === null || _b === void 0 ? void 0 : _b.viewerCountDisplayMinimum;
5153
+ if (!isValidMode(mode) || !isValidThreshold(threshold)) {
5154
+ client.log('client/getLiveViewerCountConfig', 'malformed videoStreaming settings, falling back to default', { mode, threshold });
5155
+ return DEFAULT_CONFIG;
5156
+ }
5157
+ return { mode, threshold };
5158
+ };
5159
+ /* end_public_function */
5160
+
5100
5161
  /* begin_public_function
5101
5162
  id: client.getProductCatalogueSetting
5102
5163
  */
@@ -5463,7 +5524,7 @@ const logout = async () => {
5463
5524
  const client = getActiveClient();
5464
5525
  client.log('client/api/disconnectClient');
5465
5526
  if (client.mqtt && client.mqtt.connected) {
5466
- client.mqtt.disconnect();
5527
+ await client.mqtt.disconnect({ endSession: true });
5467
5528
  }
5468
5529
  /*
5469
5530
  * for cases when session state is terminated (example on ban) or token expired,
@@ -5484,6 +5545,7 @@ const logout = async () => {
5484
5545
  client.userId = undefined;
5485
5546
  client.token = undefined;
5486
5547
  client.loginType = undefined;
5548
+ client.isGloballyBanned = false;
5487
5549
  client.http.defaults.headers.common.Authorization = '';
5488
5550
  client.http.defaults.metadata = {
5489
5551
  tokenExpiry: '',
@@ -7779,19 +7841,21 @@ const renewal = () => {
7779
7841
 
7780
7842
  const validateAccessToken = async ({ token, userId }) => {
7781
7843
  const client = getActiveClient();
7782
- // Validate token using sessions API
7783
- await client.http.get('/api/v3/sessions', {
7844
+ // Verify the token and hydrate the caller in a single call.
7845
+ const { data } = await client.http.get('/api/v4/sessions', {
7784
7846
  headers: {
7785
7847
  Authorization: `Bearer ${token.accessToken}`,
7786
7848
  },
7787
7849
  });
7788
- // Get user details
7789
- const { data: { users }, } = await client.http.get(`/api/v3/users/${userId}`, {
7790
- headers: {
7791
- Authorization: `Bearer ${token.accessToken}`,
7792
- },
7793
- });
7794
- const user = users.find((u) => u.userId === userId);
7850
+ const { users, files, userType } = data;
7851
+ const [user] = users;
7852
+ if (userId && (user === null || user === void 0 ? void 0 : user.userId) && userId !== user.userId) {
7853
+ client.log('client/api/validateAccessToken', {
7854
+ message: 'session userId does not match the token userId; using the server value',
7855
+ tokenUserId: userId,
7856
+ sessionUserId: user.userId,
7857
+ });
7858
+ }
7795
7859
  client.http.defaults.headers.common.Authorization = `Bearer ${token.accessToken}`;
7796
7860
  client.http.defaults.metadata = {
7797
7861
  tokenExpiry: token.expiresAt,
@@ -7805,6 +7869,8 @@ const validateAccessToken = async ({ token, userId }) => {
7805
7869
  isUserDeleted: false,
7806
7870
  };
7807
7871
  client.token = token;
7872
+ ingestInCache(prepareUserPayload({ users, files }));
7873
+ setCurrentUserType(userType);
7808
7874
  return user;
7809
7875
  };
7810
7876
 
@@ -7887,14 +7953,6 @@ const loginWithAccessToken = async (accessToken) => {
7887
7953
  setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7888
7954
  throw new ASCError(`User ${userId} has not been found`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
7889
7955
  }
7890
- if (user.isDeleted) {
7891
- setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7892
- throw new ASCError(`User ${userId} has been deleted`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
7893
- }
7894
- if (user.isGlobalBanned) {
7895
- setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7896
- throw new ASCError(`User ${userId} is globally banned`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
7897
- }
7898
7956
  // Set userId and login method flag
7899
7957
  client.userId = user.userId;
7900
7958
  // Set login method flag to 'accessToken' in platform-specific login session
@@ -7908,8 +7966,10 @@ const loginWithAccessToken = async (accessToken) => {
7908
7966
  catch (error) {
7909
7967
  // If error occurs, revert session state to not logged in
7910
7968
  setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7911
- // Re-throw if it's already an ASCError
7912
7969
  if (error instanceof ASCError) {
7970
+ if (error.code === 400312 /* Amity.ServerError.GLOBAL_BAN */) {
7971
+ client.isGloballyBanned = true;
7972
+ }
7913
7973
  throw error;
7914
7974
  }
7915
7975
  // Wrap other errors
@@ -7977,11 +8037,18 @@ const renewWithAccessToken = async (accessToken) => {
7977
8037
  await loginWithAccessToken(accessToken);
7978
8038
  }
7979
8039
  else {
7980
- // about to expire
7981
- await validateAccessToken({
7982
- token: tokenObject,
7983
- userId,
7984
- });
8040
+ try {
8041
+ await validateAccessToken({
8042
+ token: tokenObject,
8043
+ userId,
8044
+ });
8045
+ }
8046
+ catch (error) {
8047
+ if (error instanceof ASCError && error.code === 400312 /* Amity.ServerError.GLOBAL_BAN */) {
8048
+ client.isGloballyBanned = true;
8049
+ }
8050
+ throw error;
8051
+ }
7985
8052
  }
7986
8053
  };
7987
8054
  /* end_public_function */
@@ -7998,6 +8065,9 @@ const renewTokenWithHandler = async ({ useScheduledTask = false, }) => {
7998
8065
  if (!client.userId || !client.accessTokenHandler) {
7999
8066
  return;
8000
8067
  }
8068
+ if (client.isGloballyBanned) {
8069
+ return;
8070
+ }
8001
8071
  try {
8002
8072
  const newToken = await client.accessTokenHandler.onTokenRenew(client.userId);
8003
8073
  if (useScheduledTask) {
@@ -8596,6 +8666,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
8596
8666
  getCoreUserSettings,
8597
8667
  getSocialSettings,
8598
8668
  getChatSettings,
8669
+ getLiveViewerCountConfig,
8599
8670
  getVisitorDeviceId: getDeviceId,
8600
8671
  getMessagePreviewSetting: getMessagePreviewSetting$1,
8601
8672
  onRTEConnectionStateChange,
@@ -8735,21 +8806,13 @@ const resumeSession = async (params, sessionHandler, config) => {
8735
8806
  if (user == null) {
8736
8807
  throw new ASCError(`${params.userId} has not been found`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
8737
8808
  }
8738
- if (user.isDeleted) {
8739
- terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
8740
- return false;
8741
- }
8742
- if (user.isGlobalBanned) {
8743
- terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
8744
- return false;
8745
- }
8746
8809
  client.userId = user.userId;
8747
8810
  client.sessionHandler = sessionHandler;
8748
8811
  /*
8749
8812
  * Cannot push to subscriptions as watcher needs to continue working even if
8750
8813
  * token expires
8751
8814
  */
8752
- unsubWatcher = client.accessTokenExpiryWatcher(sessionHandler);
8815
+ unsubWatcher = client.accessTokenExpiryWatcher();
8753
8816
  setActiveUser(user);
8754
8817
  }
8755
8818
  catch (error) {
@@ -9735,6 +9798,7 @@ var index$s = /*#__PURE__*/Object.freeze({
9735
9798
  setCurrentUserType: setCurrentUserType,
9736
9799
  setAccessTokenHandler: setAccessTokenHandler,
9737
9800
  getChatSettings: getChatSettings,
9801
+ getLiveViewerCountConfig: getLiveViewerCountConfig,
9738
9802
  getCoreUserSettings: getCoreUserSettings,
9739
9803
  notifications: notifications,
9740
9804
  enableAutoSubscriptions: enableAutoSubscriptions,
@@ -12651,7 +12715,7 @@ const getWatchSessionStorage = () => {
12651
12715
  return storageInstance;
12652
12716
  };
12653
12717
 
12654
- const privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAARz+hmBgi8pJ\nQb8LeY41gtHhk+ACMwRfhsn7GqpqRQNG2qU0755mzZuVDUqjQMGSo8THJB7O+OJs\nflbZRkFXlFoFOVNw1UpNOgwEQZ6wB9oRwzepTJAfF1sVhm/o/ixvXh1zDFNDy6yZ\npXyiiJHUVxqyjllZhxnwdvjoVtDs6hW6awG09bB9nh/TTejlUKXoAgzqVwu/1QMu\nUVViET495elEe19aUarEy+oL2iKeXCEvqda/pWNBdbieFyJvvZ08HN8dPuT88wq2\njZLEAth1vrwQ2IAa4ktaLcBQdLJgIkrbDvAiVZ8lQAjS/bq5vXQikTGvoPlC5bbn\nvuOM/3eLAgMBAAECggEAVZ+peHAghq2QVj71nX5lxsNCKaCyYwixSJBpfouTt7Rz\nE6PpzMOXFi1W1o+I22jDakuSM2SOQKqI/u0QefB0r0O/KVk5NrZHXk0mkrdYtxOp\nUgaGyf8UvmjB+8VqHrNKyZdk9qtmbnNj01kTTcAtmE4H39zPR7eR/8Rul94vaZbs\nwCnKJS3mLT3JxyGug6lxanveKkjG+CKC1nJQYWaxCJxaFSzbwXQPvDhB+TvrIbee\npd5v4EAyEJohpr+T9oDGGJkb/KARBZCtwLyB976PKJwwBA8MRVL1i5QwawuMiMq5\nUtnOnbGKtCeFzaLbNU0Qi8bqyims84EQxC6DOu1fkQKBgQDdvsoBsEhsOXV7hlIJ\naEd0eSJZVkdqimxH8uGoMM2FeNaOrcB6yBXqTSP0R3OIyf8eaY6yjRvP30ZNXcll\n/gD3O1Mu6YmWQdt1W2WA6pKOsUuPXasf0pdOF7IiFZKlSabz5YHXFqwVuqm8loaj\nsXel3YWqPVdHiankE7tz+3ssnQKBgQDdqi4TNdD1MdEpihx19jr0QjUiXW3939FK\nqp30HESPEGDGQzXdmJgif9HhZb+cJSuWaHEbjgBrYahvgCF+y6LbEpOD+D/dmT+s\nDEAQaR84sah6dokwPjV8fjBSrcVFjCS+doxv0d3p/9OUEeyUhFrY03nxtIEYkLIE\n/Zvn37b4RwKBgQCLENVFe9XfsaVhQ5r9dV2iyTlmh7qgMZG5CbTFs12hQGhm8McO\n+Z7s41YSJCFr/yq1WwP4LJDtrBw99vyQr1zRsG35tNLp3gGRNzGQSQyC2uQFVHw2\np+7mNewsfhUK/gbrXNsyFnDz6635rPlhfbII3sWuP2wWXFqkxE9CbMwR7QKBgQC6\nawDMzxmo2/iYArrkyevSuEuPVxvFwpF1RgAI6C0QVCnPE38dmdN4UB7mfHekje4W\nVEercMURidPp0cxZolCYBQtilUjAyL0vqC3In1/Ogjq6oy3FEMxSop1pKxMY5j+Q\nnoqFD+6deLUrddeNH7J3X4LSr4dSbX4JjG+tlgt+yQKBgQCuwTL4hA6KqeInQ0Ta\n9VQX5Qr8hFlqJz1gpymi/k63tW/Ob8yedbg3WWNWyShwRMFYyY9S81ITFWM95uL6\nvF3x9rmRjwElJw9PMwVu6dmf/CO0Z1wzXSp2VVD12gbrUD/0/d7MUoJ9LgC8X8f/\nn0txLHYGHbx+nf95+JUg6lV3hg==\n-----END PRIVATE KEY-----";
12718
+ 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-----";
12655
12719
  /*
12656
12720
  * The crypto algorithm used for importing key and signing string
12657
12721
  */
@@ -13079,6 +13143,21 @@ const productTagLinkedObject = (productTag) => {
13079
13143
  return Object.assign(Object.assign({}, productTag), { product: internalProduct ? productLinkedObject(internalProduct) : undefined });
13080
13144
  };
13081
13145
 
13146
+ const fileLinkedObject = (file) => {
13147
+ var _a, _b, _c;
13148
+ if (!file)
13149
+ return file;
13150
+ if (file.type === 'video') {
13151
+ const video = (_b = (_a = file.attributes) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b.video;
13152
+ return Object.assign(Object.assign({}, file), { getWidth: () => { var _a; return (_a = video === null || video === void 0 ? void 0 : video.width) !== null && _a !== void 0 ? _a : 0; }, getHeight: () => { var _a; return (_a = video === null || video === void 0 ? void 0 : video.height) !== null && _a !== void 0 ? _a : 0; }, getRotation: () => { var _a; return (_a = video === null || video === void 0 ? void 0 : video.rotation) !== null && _a !== void 0 ? _a : 0; } });
13153
+ }
13154
+ if (file.type === 'image') {
13155
+ const metadata = (_c = file.attributes) === null || _c === void 0 ? void 0 : _c.metadata;
13156
+ return Object.assign(Object.assign({}, file), { getWidth: () => { var _a; return (_a = metadata === null || metadata === void 0 ? void 0 : metadata.width) !== null && _a !== void 0 ? _a : 0; }, getHeight: () => { var _a; return (_a = metadata === null || metadata === void 0 ? void 0 : metadata.height) !== null && _a !== void 0 ? _a : 0; } });
13157
+ }
13158
+ return file;
13159
+ };
13160
+
13082
13161
  const postLinkedObject = (post) => {
13083
13162
  return shallowClone(post, {
13084
13163
  childrenPosts: post.children
@@ -13117,85 +13196,99 @@ const postLinkedObject = (post) => {
13117
13196
  .filter(Boolean) || []);
13118
13197
  },
13119
13198
  get creator() {
13199
+ // The id is checked for a value, not just for presence: a payload can
13200
+ // carry the field as null, and a null segment in a cache key throws while
13201
+ // being encoded rather than simply missing the cache.
13202
+ if (!post.postedUserId)
13203
+ return undefined;
13120
13204
  const cacheData = pullFromCache(['user', 'get', post.postedUserId]);
13121
13205
  if (!(cacheData === null || cacheData === void 0 ? void 0 : cacheData.data))
13122
- return;
13206
+ return undefined;
13123
13207
  return userLinkedObject(cacheData.data);
13124
13208
  },
13125
13209
  get targetCommunity() {
13126
13210
  var _a;
13211
+ if (!post.targetId)
13212
+ return undefined;
13127
13213
  const communityCache = (_a = pullFromCache([
13128
13214
  'community',
13129
13215
  'get',
13130
13216
  post.targetId,
13131
13217
  ])) === null || _a === void 0 ? void 0 : _a.data;
13132
13218
  if (!communityCache)
13133
- return;
13219
+ return undefined;
13134
13220
  return communityLinkedObject(communityCache);
13135
13221
  },
13136
13222
  getImageInfo() {
13137
13223
  var _a, _b;
13138
- return isAmityImagePost(post)
13139
- ? (_b = pullFromCache(['file', 'get', (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.fileId])) === null || _b === void 0 ? void 0 : _b.data
13140
- : undefined;
13224
+ if (!isAmityImagePost(post) || !((_a = post.data) === null || _a === void 0 ? void 0 : _a.fileId))
13225
+ return undefined;
13226
+ return fileLinkedObject((_b = pullFromCache(['file', 'get', post.data.fileId])) === null || _b === void 0 ? void 0 : _b.data);
13141
13227
  },
13142
13228
  getVideoInfo() {
13143
13229
  var _a, _b, _c;
13144
- return isAmityVideoPost(post)
13145
- ? (_c = pullFromCache(['file', 'get', (_b = (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.videoFileId) === null || _b === void 0 ? void 0 : _b.original])) === null || _c === void 0 ? void 0 : _c.data
13146
- : undefined;
13230
+ const originalFileId = isAmityVideoPost(post) ? (_b = (_a = post.data) === null || _a === void 0 ? void 0 : _a.videoFileId) === null || _b === void 0 ? void 0 : _b.original : undefined;
13231
+ if (!originalFileId)
13232
+ return undefined;
13233
+ return fileLinkedObject((_c = pullFromCache(['file', 'get', originalFileId])) === null || _c === void 0 ? void 0 : _c.data);
13147
13234
  },
13148
13235
  getVideoThumbnailInfo() {
13149
13236
  var _a, _b;
13150
- return isAmityVideoPost(post)
13151
- ? (_b = pullFromCache(['file', 'get', (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.thumbnailFileId])) === null || _b === void 0 ? void 0 : _b.data
13152
- : undefined;
13237
+ // `isAmityVideoPost` proves the field is *present* — it tests
13238
+ // `'thumbnailFileId' in post.data` and presence is not a value. The
13239
+ // server sends the field as null until it has finished transcoding the
13240
+ // video, so a just-published post reaches here with a null id and used to
13241
+ // build the cache key ['file', 'get', null].
13242
+ const thumbnailFileId = isAmityVideoPost(post) ? (_a = post.data) === null || _a === void 0 ? void 0 : _a.thumbnailFileId : undefined;
13243
+ if (!thumbnailFileId)
13244
+ return undefined;
13245
+ return fileLinkedObject((_b = pullFromCache(['file', 'get', thumbnailFileId])) === null || _b === void 0 ? void 0 : _b.data);
13153
13246
  },
13154
13247
  getFileInfo() {
13155
13248
  var _a, _b;
13156
- return isAmityFilePost(post)
13157
- ? (_b = pullFromCache(['file', 'get', (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.fileId])) === null || _b === void 0 ? void 0 : _b.data
13158
- : undefined;
13249
+ if (!isAmityFilePost(post) || !((_a = post.data) === null || _a === void 0 ? void 0 : _a.fileId))
13250
+ return undefined;
13251
+ return (_b = pullFromCache(['file', 'get', post.data.fileId])) === null || _b === void 0 ? void 0 : _b.data;
13159
13252
  },
13160
13253
  getLivestreamInfo() {
13161
13254
  var _a, _b;
13162
- if (!isAmityLivestreamPost(post))
13163
- return;
13255
+ if (!isAmityLivestreamPost(post) || !((_a = post.data) === null || _a === void 0 ? void 0 : _a.streamId))
13256
+ return undefined;
13164
13257
  const cache = (_b = pullFromCache([
13165
13258
  'stream',
13166
13259
  'get',
13167
- (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.streamId,
13260
+ post.data.streamId,
13168
13261
  ])) === null || _b === void 0 ? void 0 : _b.data;
13169
13262
  if (!cache)
13170
- return;
13263
+ return undefined;
13171
13264
  return streamLinkedObject(cache);
13172
13265
  },
13173
13266
  getPollInfo() {
13174
13267
  var _a, _b;
13175
- if (!isAmityPollPost(post))
13176
- return;
13177
- const cache = (_b = pullFromCache(['poll', 'get', (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.pollId])) === null || _b === void 0 ? void 0 : _b.data;
13268
+ if (!isAmityPollPost(post) || !((_a = post.data) === null || _a === void 0 ? void 0 : _a.pollId))
13269
+ return undefined;
13270
+ const cache = (_b = pullFromCache(['poll', 'get', post.data.pollId])) === null || _b === void 0 ? void 0 : _b.data;
13178
13271
  if (!cache)
13179
- return;
13272
+ return undefined;
13180
13273
  return pollLinkedObject(cache);
13181
13274
  },
13182
13275
  getClipInfo() {
13183
13276
  var _a, _b;
13184
- return isAmityClipPost(post)
13185
- ? (_b = pullFromCache(['file', 'get', (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.fileId])) === null || _b === void 0 ? void 0 : _b.data
13186
- : undefined;
13277
+ if (!isAmityClipPost(post) || !((_a = post.data) === null || _a === void 0 ? void 0 : _a.fileId))
13278
+ return undefined;
13279
+ return (_b = pullFromCache(['file', 'get', post.data.fileId])) === null || _b === void 0 ? void 0 : _b.data;
13187
13280
  },
13188
13281
  getAudioInfo() {
13189
13282
  var _a, _b;
13190
- return isAmityAudioPost(post)
13191
- ? (_b = pullFromCache(['file', 'get', (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.fileId])) === null || _b === void 0 ? void 0 : _b.data
13192
- : undefined;
13283
+ if (!isAmityAudioPost(post) || !((_a = post.data) === null || _a === void 0 ? void 0 : _a.fileId))
13284
+ return undefined;
13285
+ return (_b = pullFromCache(['file', 'get', post.data.fileId])) === null || _b === void 0 ? void 0 : _b.data;
13193
13286
  },
13194
13287
  getRoomInfo() {
13195
13288
  var _a, _b;
13196
- if (!isAmityRoomPost(post))
13197
- return;
13198
- const room = (_b = pullFromCache(['room', 'get', (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.roomId])) === null || _b === void 0 ? void 0 : _b.data;
13289
+ if (!isAmityRoomPost(post) || !((_a = post.data) === null || _a === void 0 ? void 0 : _a.roomId))
13290
+ return undefined;
13291
+ const room = (_b = pullFromCache(['room', 'get', post.data.roomId])) === null || _b === void 0 ? void 0 : _b.data;
13199
13292
  return room ? roomLinkedObject(room) : undefined;
13200
13293
  },
13201
13294
  getEventInfo() {
@@ -14139,6 +14232,7 @@ const eventLinkedObject = (event) => {
14139
14232
  };
14140
14233
 
14141
14234
  const LinkedObject = {
14235
+ file: fileLinkedObject,
14142
14236
  ad: adLinkedObject,
14143
14237
  comment: commentLinkedObject,
14144
14238
  post: postLinkedObject,
@@ -15302,10 +15396,58 @@ class SearchUserLiveCollectionController extends LiveCollectionController {
15302
15396
  }
15303
15397
  }
15304
15398
 
15399
+ /* begin_public_function
15400
+ id: user.searchUsers
15401
+ */
15402
+ /**
15403
+ * ```js
15404
+ * import { UserRepository } from '@amityco/ts-sdk'
15405
+ *
15406
+ * let users = []
15407
+ * const unsub = UserRepository.searchUsers(
15408
+ * { displayName: 'jack', searchBy: [SearchUsersByEnum.DISPLAY_NAME] },
15409
+ * response => merge(users, response.data),
15410
+ * )
15411
+ * ```
15412
+ *
15413
+ * Observe all mutations on a list of {@link Amity.InternalUser}s.
15414
+ *
15415
+ * Pass `searchBy` in `params` to restrict which user fields are matched
15416
+ * (e.g. `[SearchUsersByEnum.DISPLAY_NAME]`). When omitted, the backend
15417
+ * default (both `displayName` and `userId`) applies.
15418
+ *
15419
+ * @param params for searching users
15420
+ * @param callback the function to call when new data are available
15421
+ * @param config the configuration for the live collection
15422
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the users
15423
+ *
15424
+ * @category Category Live Collection
15425
+ */
15426
+ const searchUsers = (params, callback, config) => {
15427
+ const { log, cache } = getActiveClient();
15428
+ if (!cache) {
15429
+ // eslint-disable-next-line no-console
15430
+ console.log(ENABLE_CACHE_MESSAGE);
15431
+ }
15432
+ const timestamp = Date.now();
15433
+ log(`liveSearchUsers(tmpid: ${timestamp}) > listen`);
15434
+ const searchUsersLiveCollection = new SearchUserLiveCollectionController(params, callback);
15435
+ const disposers = searchUsersLiveCollection.startSubscription();
15436
+ const cacheKey = searchUsersLiveCollection.getCacheKey();
15437
+ disposers.push(() => dropFromCache(cacheKey));
15438
+ return () => {
15439
+ log(`liveSearchUsers(tmpid: ${timestamp}) > dispose`);
15440
+ disposers.forEach(fn => fn());
15441
+ };
15442
+ };
15443
+ /* end_public_function */
15444
+
15305
15445
  /* begin_public_function
15306
15446
  id: user.search
15307
15447
  */
15308
15448
  /**
15449
+ * @deprecated Use {@link searchUsers} instead. `searchUserByDisplayName` will be removed in a future major version.
15450
+ *
15309
15451
  * ```js
15310
15452
  * import { UserRepository } from '@amityco/ts-sdk-react-native'
15311
15453
  *
@@ -15454,6 +15596,7 @@ var index$q = /*#__PURE__*/Object.freeze({
15454
15596
  getUsers: getUsers,
15455
15597
  getBlockedUsers: getBlockedUsers,
15456
15598
  getBlockingUsers: getBlockingUsers,
15599
+ searchUsers: searchUsers,
15457
15600
  searchUserByDisplayName: searchUserByDisplayName,
15458
15601
  getReachedUsers: getReachedUsers,
15459
15602
  get AmityUserSearchMatchType () { return AmityUserSearchMatchType; }
@@ -15486,7 +15629,7 @@ const getFile = async (fileId) => {
15486
15629
  if (client.cache)
15487
15630
  ingestInCache({ files: [data] }, { cachedAt });
15488
15631
  return {
15489
- data,
15632
+ data: fileLinkedObject(data),
15490
15633
  cachedAt,
15491
15634
  };
15492
15635
  };
@@ -15513,7 +15656,7 @@ getFile.locally = (fileId) => {
15513
15656
  if (!cached)
15514
15657
  return;
15515
15658
  return {
15516
- data: cached.data,
15659
+ data: fileLinkedObject(cached.data),
15517
15660
  cachedAt: cached.cachedAt,
15518
15661
  };
15519
15662
  };
@@ -15650,7 +15793,7 @@ const uploadVideo = async (formData, feedType, onProgress) => {
15650
15793
  if (client.cache)
15651
15794
  ingestInCache({ files: data }, { cachedAt });
15652
15795
  return {
15653
- data,
15796
+ data: data.map(file => fileLinkedObject(file)),
15654
15797
  cachedAt,
15655
15798
  };
15656
15799
  };
@@ -15711,7 +15854,7 @@ const uploadImage = async (formData, onProgress, altText) => {
15711
15854
  if (client.cache)
15712
15855
  ingestInCache({ files: data }, { cachedAt });
15713
15856
  return {
15714
- data,
15857
+ data: data.map(file => fileLinkedObject(file)),
15715
15858
  cachedAt,
15716
15859
  };
15717
15860
  };
@@ -16674,39 +16817,6 @@ removeReaction.optimistically = (referenceType, referenceId, reactionName) => {
16674
16817
  return !((_d = reaction === null || reaction === void 0 ? void 0 : reaction.myReactions) === null || _d === void 0 ? void 0 : _d.includes(reactionName));
16675
16818
  };
16676
16819
 
16677
- /**
16678
- * Resolves the id of the parent post that a child-post payload belongs to.
16679
- *
16680
- * `parentId` and `parentPostId` name the same post, but a payload does not
16681
- * always carry both — and the delete/create child handlers decide *whether* a
16682
- * post is a child from `parentId` while reading the cache with `parentPostId`.
16683
- * When only the former is set that read builds `['post', 'get', undefined]`,
16684
- * which cannot match anything and, when the value is null, breaks key encoding
16685
- * outright. Reading whichever id is present keeps the decision and the lookup
16686
- * on the same post.
16687
- *
16688
- * @param post the child post payload
16689
- * @returns the parent post id, or undefined when the payload carries neither
16690
- *
16691
- * @category Post Events
16692
- * @hidden
16693
- */
16694
- const resolveParentPostId = (post) => {
16695
- if (post.parentPostId)
16696
- return post.parentPostId;
16697
- if (post.parentId) {
16698
- // Diagnostic: we do not know yet whether the server actually emits this
16699
- // shape. If this warning is never seen in practice the fallback can go.
16700
- console.warn('[AmitySDK] post payload carries `parentId` without `parentPostId` — falling back to `parentId`', {
16701
- postId: post.postId,
16702
- parentId: post.parentId,
16703
- parentPostId: post.parentPostId,
16704
- });
16705
- return post.parentId;
16706
- }
16707
- return undefined;
16708
- };
16709
-
16710
16820
  const processDeleteChildPost = (payload) => {
16711
16821
  var _a;
16712
16822
  const post = payload.posts[0];
@@ -16718,10 +16828,7 @@ const processDeleteChildPost = (payload) => {
16718
16828
  }
16719
16829
  else {
16720
16830
  // child post in a parent post
16721
- const parentPostId = resolveParentPostId(post);
16722
- if (!parentPostId)
16723
- return;
16724
- const parentPost = (_a = pullFromCache(['post', 'get', parentPostId])) === null || _a === void 0 ? void 0 : _a.data;
16831
+ const parentPost = (_a = pullFromCache(['post', 'get', post.parentPostId])) === null || _a === void 0 ? void 0 : _a.data;
16725
16832
  if (!parentPost)
16726
16833
  return;
16727
16834
  pushToCache(['post', 'get', parentPost.postId], Object.assign(Object.assign({}, parentPost), { children: parentPost.children.filter(childId => childId !== post.postId) }));
@@ -16732,10 +16839,7 @@ const processCreateChildPost = (payload) => {
16732
16839
  const post = payload.posts[0];
16733
16840
  if (!post.parentId)
16734
16841
  return;
16735
- const parentPostId = resolveParentPostId(post);
16736
- if (!parentPostId)
16737
- return;
16738
- const parentPost = (_a = pullFromCache(['post', 'get', parentPostId])) === null || _a === void 0 ? void 0 : _a.data;
16842
+ const parentPost = (_a = pullFromCache(['post', 'get', post.parentPostId])) === null || _a === void 0 ? void 0 : _a.data;
16739
16843
  if (!parentPost)
16740
16844
  return;
16741
16845
  pushToCache(['post', 'get', parentPost.postId], Object.assign(Object.assign({}, parentPost), { children: [...new Set([post.postId, ...parentPost.children])] }));