@amityco/ts-sdk-react-native 7.26.1-c29647b8.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 (57) 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/cache/utils/index.d.ts.map +1 -1
  14. package/dist/client/api/createClient.d.ts.map +1 -1
  15. package/dist/client/api/getLiveViewerCountConfig.d.ts +24 -0
  16. package/dist/client/api/getLiveViewerCountConfig.d.ts.map +1 -0
  17. package/dist/client/api/index.d.ts +1 -0
  18. package/dist/client/api/index.d.ts.map +1 -1
  19. package/dist/client/api/loginWithAccessToken.d.ts.map +1 -1
  20. package/dist/client/api/logout.d.ts.map +1 -1
  21. package/dist/client/api/renewTokenWithHandler.d.ts.map +1 -1
  22. package/dist/client/api/renewWithAccessToken.d.ts.map +1 -1
  23. package/dist/client/api/resumeSession.d.ts.map +1 -1
  24. package/dist/client/api/tests/renewTokenWithHandler.test.d.ts +2 -0
  25. package/dist/client/api/tests/renewTokenWithHandler.test.d.ts.map +1 -0
  26. package/dist/client/api/tests/renewWithAccessToken.test.d.ts +2 -0
  27. package/dist/client/api/tests/renewWithAccessToken.test.d.ts.map +1 -0
  28. package/dist/client/api/tests/validateAccessToken.test.d.ts +2 -0
  29. package/dist/client/api/tests/validateAccessToken.test.d.ts.map +1 -0
  30. package/dist/client/api/validateAccessToken.d.ts +1 -1
  31. package/dist/client/api/validateAccessToken.d.ts.map +1 -1
  32. package/dist/client/utils/endpoints.d.ts +1 -1
  33. package/dist/client/utils/endpoints.d.ts.map +1 -1
  34. package/dist/core/transports/mqtt.d.ts.map +1 -1
  35. package/dist/fileRepository/api/getFile.d.ts.map +1 -1
  36. package/dist/fileRepository/api/uploadImage.d.ts.map +1 -1
  37. package/dist/fileRepository/api/uploadVideo.d.ts.map +1 -1
  38. package/dist/index.cjs.js +227 -79
  39. package/dist/index.esm.js +228 -80
  40. package/dist/index.umd.js +1 -1
  41. package/dist/userRepository/observers/index.d.ts +1 -0
  42. package/dist/userRepository/observers/index.d.ts.map +1 -1
  43. package/dist/userRepository/observers/searchUserByDisplayName.d.ts +2 -0
  44. package/dist/userRepository/observers/searchUserByDisplayName.d.ts.map +1 -1
  45. package/dist/userRepository/observers/searchUsers.d.ts +26 -0
  46. package/dist/userRepository/observers/searchUsers.d.ts.map +1 -0
  47. package/dist/userRepository/observers/tests/integrations/searchUsers.integration.test.d.ts +2 -0
  48. package/dist/userRepository/observers/tests/integrations/searchUsers.integration.test.d.ts.map +1 -0
  49. package/dist/userRepository/observers/tests/searchUsers.test.d.ts +2 -0
  50. package/dist/userRepository/observers/tests/searchUsers.test.d.ts.map +1 -0
  51. package/dist/utils/linkedObject/fileLinkedObject.d.ts +2 -0
  52. package/dist/utils/linkedObject/fileLinkedObject.d.ts.map +1 -0
  53. package/dist/utils/linkedObject/index.d.ts +1 -0
  54. package/dist/utils/linkedObject/index.d.ts.map +1 -1
  55. package/dist/utils/linkedObject/postLinkedObject.d.ts.map +1 -1
  56. package/dist/utils/tests/dummy/file.d.ts.map +1 -1
  57. package/package.json +1 -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__';
@@ -399,7 +406,13 @@ const normalize = (source) => Object.keys(source)
399
406
  * @category Cache
400
407
  * @hidden
401
408
  */
402
- const encodeKey = (key) => JSON.stringify(key, (_, val) => (typeof val === 'object' ? normalize(val) : val));
409
+ const encodeKey = (key) => JSON.stringify(key, (_, val) =>
410
+ // `typeof null` is `'object'`, so a nullish segment would reach normalize()
411
+ // and throw on Object.keys(null) — taking down whichever cache read built
412
+ // the key. Amity.Serializable does not admit null in the first place, so a
413
+ // null here is a payload that broke its own contract: encode it as null and
414
+ // let the miss be a miss.
415
+ val !== null && typeof val === 'object' ? normalize(val) : val);
403
416
  /**
404
417
  * Decodes a string back into a {@link Amity.CacheKey}
405
418
 
@@ -1966,8 +1979,7 @@ const API_REGIONS = {
1966
1979
  };
1967
1980
  const URLS = {
1968
1981
  http: 'https://apix.{region}.amity.co',
1969
- // upload: 'https://upload.{region}.amity.co',
1970
- upload: 'https://apix.{region}.amity.co',
1982
+ upload: 'https://upload.{region}.amity.co',
1971
1983
  mqtt: 'wss://sse.{region}.amity.co:443/mqtt',
1972
1984
  };
1973
1985
  function computeUrl(type, region) {
@@ -2491,10 +2503,11 @@ var MqttError;
2491
2503
  MqttError[MqttError["BAD_USERNAME_OR_PASSWORD"] = 134] = "BAD_USERNAME_OR_PASSWORD";
2492
2504
  MqttError[MqttError["NOT_AUTHORIZED"] = 135] = "NOT_AUTHORIZED";
2493
2505
  })(MqttError || (MqttError = {}));
2494
- // MQTT 5 session expiry, in seconds. 0xFFFFFFFF keeps the session alive
2495
- // indefinitely, matching the previous 3.1.1 `clean: false` behaviour where the
2496
- // broker retained the session (and its subscriptions) across disconnects.
2497
- 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;
2498
2511
  function getMqttOptions(params) {
2499
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,
2500
2513
  // The broker/LB drops idle sockets at ~60s. mqtt.js v5 sends its first
@@ -2611,8 +2624,16 @@ const createMqttTransport = (endpoint) => {
2611
2624
  }
2612
2625
  return {
2613
2626
  connect,
2614
- async disconnect() {
2627
+ async disconnect(options) {
2615
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
+ }
2616
2637
  return new Promise(resolve => mqttClient === null || mqttClient === void 0 ? void 0 : mqttClient.end(true, undefined, () => resolve()));
2617
2638
  }
2618
2639
  },
@@ -5092,6 +5113,51 @@ const getCoreUserSettings = async () => {
5092
5113
  return data;
5093
5114
  };
5094
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
+
5095
5161
  /* begin_public_function
5096
5162
  id: client.getProductCatalogueSetting
5097
5163
  */
@@ -5458,7 +5524,7 @@ const logout = async () => {
5458
5524
  const client = getActiveClient();
5459
5525
  client.log('client/api/disconnectClient');
5460
5526
  if (client.mqtt && client.mqtt.connected) {
5461
- client.mqtt.disconnect();
5527
+ await client.mqtt.disconnect({ endSession: true });
5462
5528
  }
5463
5529
  /*
5464
5530
  * for cases when session state is terminated (example on ban) or token expired,
@@ -5479,6 +5545,7 @@ const logout = async () => {
5479
5545
  client.userId = undefined;
5480
5546
  client.token = undefined;
5481
5547
  client.loginType = undefined;
5548
+ client.isGloballyBanned = false;
5482
5549
  client.http.defaults.headers.common.Authorization = '';
5483
5550
  client.http.defaults.metadata = {
5484
5551
  tokenExpiry: '',
@@ -7774,19 +7841,21 @@ const renewal = () => {
7774
7841
 
7775
7842
  const validateAccessToken = async ({ token, userId }) => {
7776
7843
  const client = getActiveClient();
7777
- // Validate token using sessions API
7778
- await client.http.get('/api/v3/sessions', {
7779
- headers: {
7780
- Authorization: `Bearer ${token.accessToken}`,
7781
- },
7782
- });
7783
- // Get user details
7784
- const { data: { users }, } = await client.http.get(`/api/v3/users/${userId}`, {
7844
+ // Verify the token and hydrate the caller in a single call.
7845
+ const { data } = await client.http.get('/api/v4/sessions', {
7785
7846
  headers: {
7786
7847
  Authorization: `Bearer ${token.accessToken}`,
7787
7848
  },
7788
7849
  });
7789
- 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
+ }
7790
7859
  client.http.defaults.headers.common.Authorization = `Bearer ${token.accessToken}`;
7791
7860
  client.http.defaults.metadata = {
7792
7861
  tokenExpiry: token.expiresAt,
@@ -7800,6 +7869,8 @@ const validateAccessToken = async ({ token, userId }) => {
7800
7869
  isUserDeleted: false,
7801
7870
  };
7802
7871
  client.token = token;
7872
+ ingestInCache(prepareUserPayload({ users, files }));
7873
+ setCurrentUserType(userType);
7803
7874
  return user;
7804
7875
  };
7805
7876
 
@@ -7882,14 +7953,6 @@ const loginWithAccessToken = async (accessToken) => {
7882
7953
  setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7883
7954
  throw new ASCError(`User ${userId} has not been found`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
7884
7955
  }
7885
- if (user.isDeleted) {
7886
- setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7887
- throw new ASCError(`User ${userId} has been deleted`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
7888
- }
7889
- if (user.isGlobalBanned) {
7890
- setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7891
- throw new ASCError(`User ${userId} is globally banned`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
7892
- }
7893
7956
  // Set userId and login method flag
7894
7957
  client.userId = user.userId;
7895
7958
  // Set login method flag to 'accessToken' in platform-specific login session
@@ -7903,8 +7966,10 @@ const loginWithAccessToken = async (accessToken) => {
7903
7966
  catch (error) {
7904
7967
  // If error occurs, revert session state to not logged in
7905
7968
  setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7906
- // Re-throw if it's already an ASCError
7907
7969
  if (error instanceof ASCError) {
7970
+ if (error.code === 400312 /* Amity.ServerError.GLOBAL_BAN */) {
7971
+ client.isGloballyBanned = true;
7972
+ }
7908
7973
  throw error;
7909
7974
  }
7910
7975
  // Wrap other errors
@@ -7972,11 +8037,18 @@ const renewWithAccessToken = async (accessToken) => {
7972
8037
  await loginWithAccessToken(accessToken);
7973
8038
  }
7974
8039
  else {
7975
- // about to expire
7976
- await validateAccessToken({
7977
- token: tokenObject,
7978
- userId,
7979
- });
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
+ }
7980
8052
  }
7981
8053
  };
7982
8054
  /* end_public_function */
@@ -7993,6 +8065,9 @@ const renewTokenWithHandler = async ({ useScheduledTask = false, }) => {
7993
8065
  if (!client.userId || !client.accessTokenHandler) {
7994
8066
  return;
7995
8067
  }
8068
+ if (client.isGloballyBanned) {
8069
+ return;
8070
+ }
7996
8071
  try {
7997
8072
  const newToken = await client.accessTokenHandler.onTokenRenew(client.userId);
7998
8073
  if (useScheduledTask) {
@@ -8591,6 +8666,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
8591
8666
  getCoreUserSettings,
8592
8667
  getSocialSettings,
8593
8668
  getChatSettings,
8669
+ getLiveViewerCountConfig,
8594
8670
  getVisitorDeviceId: getDeviceId,
8595
8671
  getMessagePreviewSetting: getMessagePreviewSetting$1,
8596
8672
  onRTEConnectionStateChange,
@@ -8730,21 +8806,13 @@ const resumeSession = async (params, sessionHandler, config) => {
8730
8806
  if (user == null) {
8731
8807
  throw new ASCError(`${params.userId} has not been found`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
8732
8808
  }
8733
- if (user.isDeleted) {
8734
- terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
8735
- return false;
8736
- }
8737
- if (user.isGlobalBanned) {
8738
- terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
8739
- return false;
8740
- }
8741
8809
  client.userId = user.userId;
8742
8810
  client.sessionHandler = sessionHandler;
8743
8811
  /*
8744
8812
  * Cannot push to subscriptions as watcher needs to continue working even if
8745
8813
  * token expires
8746
8814
  */
8747
- unsubWatcher = client.accessTokenExpiryWatcher(sessionHandler);
8815
+ unsubWatcher = client.accessTokenExpiryWatcher();
8748
8816
  setActiveUser(user);
8749
8817
  }
8750
8818
  catch (error) {
@@ -9730,6 +9798,7 @@ var index$s = /*#__PURE__*/Object.freeze({
9730
9798
  setCurrentUserType: setCurrentUserType,
9731
9799
  setAccessTokenHandler: setAccessTokenHandler,
9732
9800
  getChatSettings: getChatSettings,
9801
+ getLiveViewerCountConfig: getLiveViewerCountConfig,
9733
9802
  getCoreUserSettings: getCoreUserSettings,
9734
9803
  notifications: notifications,
9735
9804
  enableAutoSubscriptions: enableAutoSubscriptions,
@@ -12646,7 +12715,7 @@ const getWatchSessionStorage = () => {
12646
12715
  return storageInstance;
12647
12716
  };
12648
12717
 
12649
- 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-----";
12650
12719
  /*
12651
12720
  * The crypto algorithm used for importing key and signing string
12652
12721
  */
@@ -13074,6 +13143,21 @@ const productTagLinkedObject = (productTag) => {
13074
13143
  return Object.assign(Object.assign({}, productTag), { product: internalProduct ? productLinkedObject(internalProduct) : undefined });
13075
13144
  };
13076
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
+
13077
13161
  const postLinkedObject = (post) => {
13078
13162
  return shallowClone(post, {
13079
13163
  childrenPosts: post.children
@@ -13112,85 +13196,99 @@ const postLinkedObject = (post) => {
13112
13196
  .filter(Boolean) || []);
13113
13197
  },
13114
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;
13115
13204
  const cacheData = pullFromCache(['user', 'get', post.postedUserId]);
13116
13205
  if (!(cacheData === null || cacheData === void 0 ? void 0 : cacheData.data))
13117
- return;
13206
+ return undefined;
13118
13207
  return userLinkedObject(cacheData.data);
13119
13208
  },
13120
13209
  get targetCommunity() {
13121
13210
  var _a;
13211
+ if (!post.targetId)
13212
+ return undefined;
13122
13213
  const communityCache = (_a = pullFromCache([
13123
13214
  'community',
13124
13215
  'get',
13125
13216
  post.targetId,
13126
13217
  ])) === null || _a === void 0 ? void 0 : _a.data;
13127
13218
  if (!communityCache)
13128
- return;
13219
+ return undefined;
13129
13220
  return communityLinkedObject(communityCache);
13130
13221
  },
13131
13222
  getImageInfo() {
13132
13223
  var _a, _b;
13133
- return isAmityImagePost(post)
13134
- ? (_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
13135
- : 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);
13136
13227
  },
13137
13228
  getVideoInfo() {
13138
13229
  var _a, _b, _c;
13139
- return isAmityVideoPost(post)
13140
- ? (_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
13141
- : 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);
13142
13234
  },
13143
13235
  getVideoThumbnailInfo() {
13144
13236
  var _a, _b;
13145
- return isAmityVideoPost(post)
13146
- ? (_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
13147
- : 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);
13148
13246
  },
13149
13247
  getFileInfo() {
13150
13248
  var _a, _b;
13151
- return isAmityFilePost(post)
13152
- ? (_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
13153
- : 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;
13154
13252
  },
13155
13253
  getLivestreamInfo() {
13156
13254
  var _a, _b;
13157
- if (!isAmityLivestreamPost(post))
13158
- return;
13255
+ if (!isAmityLivestreamPost(post) || !((_a = post.data) === null || _a === void 0 ? void 0 : _a.streamId))
13256
+ return undefined;
13159
13257
  const cache = (_b = pullFromCache([
13160
13258
  'stream',
13161
13259
  'get',
13162
- (_a = post === null || post === void 0 ? void 0 : post.data) === null || _a === void 0 ? void 0 : _a.streamId,
13260
+ post.data.streamId,
13163
13261
  ])) === null || _b === void 0 ? void 0 : _b.data;
13164
13262
  if (!cache)
13165
- return;
13263
+ return undefined;
13166
13264
  return streamLinkedObject(cache);
13167
13265
  },
13168
13266
  getPollInfo() {
13169
13267
  var _a, _b;
13170
- if (!isAmityPollPost(post))
13171
- return;
13172
- 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;
13173
13271
  if (!cache)
13174
- return;
13272
+ return undefined;
13175
13273
  return pollLinkedObject(cache);
13176
13274
  },
13177
13275
  getClipInfo() {
13178
13276
  var _a, _b;
13179
- return isAmityClipPost(post)
13180
- ? (_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
13181
- : 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;
13182
13280
  },
13183
13281
  getAudioInfo() {
13184
13282
  var _a, _b;
13185
- return isAmityAudioPost(post)
13186
- ? (_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
13187
- : 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;
13188
13286
  },
13189
13287
  getRoomInfo() {
13190
13288
  var _a, _b;
13191
- if (!isAmityRoomPost(post))
13192
- return;
13193
- 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;
13194
13292
  return room ? roomLinkedObject(room) : undefined;
13195
13293
  },
13196
13294
  getEventInfo() {
@@ -14134,6 +14232,7 @@ const eventLinkedObject = (event) => {
14134
14232
  };
14135
14233
 
14136
14234
  const LinkedObject = {
14235
+ file: fileLinkedObject,
14137
14236
  ad: adLinkedObject,
14138
14237
  comment: commentLinkedObject,
14139
14238
  post: postLinkedObject,
@@ -15297,10 +15396,58 @@ class SearchUserLiveCollectionController extends LiveCollectionController {
15297
15396
  }
15298
15397
  }
15299
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
+
15300
15445
  /* begin_public_function
15301
15446
  id: user.search
15302
15447
  */
15303
15448
  /**
15449
+ * @deprecated Use {@link searchUsers} instead. `searchUserByDisplayName` will be removed in a future major version.
15450
+ *
15304
15451
  * ```js
15305
15452
  * import { UserRepository } from '@amityco/ts-sdk-react-native'
15306
15453
  *
@@ -15449,6 +15596,7 @@ var index$q = /*#__PURE__*/Object.freeze({
15449
15596
  getUsers: getUsers,
15450
15597
  getBlockedUsers: getBlockedUsers,
15451
15598
  getBlockingUsers: getBlockingUsers,
15599
+ searchUsers: searchUsers,
15452
15600
  searchUserByDisplayName: searchUserByDisplayName,
15453
15601
  getReachedUsers: getReachedUsers,
15454
15602
  get AmityUserSearchMatchType () { return AmityUserSearchMatchType; }
@@ -15481,7 +15629,7 @@ const getFile = async (fileId) => {
15481
15629
  if (client.cache)
15482
15630
  ingestInCache({ files: [data] }, { cachedAt });
15483
15631
  return {
15484
- data,
15632
+ data: fileLinkedObject(data),
15485
15633
  cachedAt,
15486
15634
  };
15487
15635
  };
@@ -15508,7 +15656,7 @@ getFile.locally = (fileId) => {
15508
15656
  if (!cached)
15509
15657
  return;
15510
15658
  return {
15511
- data: cached.data,
15659
+ data: fileLinkedObject(cached.data),
15512
15660
  cachedAt: cached.cachedAt,
15513
15661
  };
15514
15662
  };
@@ -15645,7 +15793,7 @@ const uploadVideo = async (formData, feedType, onProgress) => {
15645
15793
  if (client.cache)
15646
15794
  ingestInCache({ files: data }, { cachedAt });
15647
15795
  return {
15648
- data,
15796
+ data: data.map(file => fileLinkedObject(file)),
15649
15797
  cachedAt,
15650
15798
  };
15651
15799
  };
@@ -15706,7 +15854,7 @@ const uploadImage = async (formData, onProgress, altText) => {
15706
15854
  if (client.cache)
15707
15855
  ingestInCache({ files: data }, { cachedAt });
15708
15856
  return {
15709
- data,
15857
+ data: data.map(file => fileLinkedObject(file)),
15710
15858
  cachedAt,
15711
15859
  };
15712
15860
  };