@sendbird/uikit-utils 2.4.1 → 2.5.0-rc.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 (78) hide show
  1. package/README.md +1 -1
  2. package/lib/commonjs/hooks/index.js +12 -31
  3. package/lib/commonjs/hooks/index.js.map +1 -1
  4. package/lib/commonjs/hooks/react-native.js +2 -11
  5. package/lib/commonjs/hooks/react-native.js.map +1 -1
  6. package/lib/commonjs/index.js +16 -45
  7. package/lib/commonjs/index.js.map +1 -1
  8. package/lib/commonjs/sendbird/attrs.js +8 -11
  9. package/lib/commonjs/sendbird/attrs.js.map +1 -1
  10. package/lib/commonjs/sendbird/channel.js +0 -16
  11. package/lib/commonjs/sendbird/channel.js.map +1 -1
  12. package/lib/commonjs/sendbird/message.js +13 -34
  13. package/lib/commonjs/sendbird/message.js.map +1 -1
  14. package/lib/commonjs/sendbird/user.js +0 -2
  15. package/lib/commonjs/sendbird/user.js.map +1 -1
  16. package/lib/commonjs/shared/arrayToMap.js +0 -6
  17. package/lib/commonjs/shared/arrayToMap.js.map +1 -1
  18. package/lib/commonjs/shared/bufferedRequest.js +5 -26
  19. package/lib/commonjs/shared/bufferedRequest.js.map +1 -1
  20. package/lib/commonjs/shared/file.js +11 -28
  21. package/lib/commonjs/shared/file.js.map +1 -1
  22. package/lib/commonjs/shared/index.js +3 -7
  23. package/lib/commonjs/shared/index.js.map +1 -1
  24. package/lib/commonjs/shared/logger.js +3 -22
  25. package/lib/commonjs/shared/logger.js.map +1 -1
  26. package/lib/commonjs/shared/regex.js +2 -9
  27. package/lib/commonjs/shared/regex.js.map +1 -1
  28. package/lib/commonjs/types.js.map +1 -1
  29. package/lib/commonjs/ui-format/common.js +62 -18
  30. package/lib/commonjs/ui-format/common.js.map +1 -1
  31. package/lib/commonjs/ui-format/groupChannel.js +2 -48
  32. package/lib/commonjs/ui-format/groupChannel.js.map +1 -1
  33. package/lib/commonjs/ui-format/openChannel.js +0 -4
  34. package/lib/commonjs/ui-format/openChannel.js.map +1 -1
  35. package/lib/module/hooks/index.js +10 -7
  36. package/lib/module/hooks/index.js.map +1 -1
  37. package/lib/module/hooks/react-native.js +2 -2
  38. package/lib/module/hooks/react-native.js.map +1 -1
  39. package/lib/module/index.js +5 -3
  40. package/lib/module/index.js.map +1 -1
  41. package/lib/module/sendbird/attrs.js +6 -9
  42. package/lib/module/sendbird/attrs.js.map +1 -1
  43. package/lib/module/sendbird/channel.js +0 -1
  44. package/lib/module/sendbird/channel.js.map +1 -1
  45. package/lib/module/sendbird/message.js +12 -17
  46. package/lib/module/sendbird/message.js.map +1 -1
  47. package/lib/module/sendbird/user.js.map +1 -1
  48. package/lib/module/shared/arrayToMap.js +0 -4
  49. package/lib/module/shared/arrayToMap.js.map +1 -1
  50. package/lib/module/shared/bufferedRequest.js +5 -24
  51. package/lib/module/shared/bufferedRequest.js.map +1 -1
  52. package/lib/module/shared/file.js +11 -16
  53. package/lib/module/shared/file.js.map +1 -1
  54. package/lib/module/shared/index.js +3 -3
  55. package/lib/module/shared/index.js.map +1 -1
  56. package/lib/module/shared/logger.js +3 -21
  57. package/lib/module/shared/logger.js.map +1 -1
  58. package/lib/module/shared/regex.js +3 -2
  59. package/lib/module/shared/regex.js.map +1 -1
  60. package/lib/module/types.js.map +1 -1
  61. package/lib/module/ui-format/common.js +60 -10
  62. package/lib/module/ui-format/common.js.map +1 -1
  63. package/lib/module/ui-format/groupChannel.js +3 -41
  64. package/lib/module/ui-format/groupChannel.js.map +1 -1
  65. package/lib/module/ui-format/openChannel.js.map +1 -1
  66. package/lib/typescript/src/hooks/index.d.ts +1 -0
  67. package/lib/typescript/src/index.d.ts +5 -4
  68. package/lib/typescript/src/sendbird/message.d.ts +8 -1
  69. package/lib/typescript/src/types.d.ts +2 -1
  70. package/lib/typescript/src/ui-format/common.d.ts +13 -0
  71. package/lib/typescript/src/ui-format/groupChannel.d.ts +1 -1
  72. package/package.json +11 -8
  73. package/src/hooks/index.ts +10 -0
  74. package/src/index.ts +5 -52
  75. package/src/sendbird/message.ts +12 -0
  76. package/src/types.ts +2 -0
  77. package/src/ui-format/common.ts +53 -1
  78. package/src/ui-format/groupChannel.ts +4 -30
@@ -21,11 +21,12 @@ export declare const isFunction: (param?: unknown) => param is Function;
21
21
  export declare function ifThenOr<T>(cond: boolean, then: T): T | undefined;
22
22
  export declare function ifThenOr<T, V>(cond: boolean, then: T, or: V): T | V;
23
23
  export declare const SBErrorCode: {
24
- NON_AUTHORIZED: number;
25
- CHANNEL_NOT_FOUND_SERVER: number;
26
- CHANNEL_NOT_FOUND_SDK: number;
24
+ UNAUTHORIZED_REQUEST: number;
25
+ RESOURCE_NOT_FOUND: number;
26
+ BANNED_USER_SEND_MESSAGE_NOT_ALLOWED: number;
27
+ CHANNEL_NOT_FOUND: number;
27
28
  };
28
29
  export declare const SBErrorMessage: {
29
30
  ACL: string;
30
31
  };
31
- export type { UserStruct, FilterByValueType, UnionToIntersection, OmittedValues, PartialDeep, Optional, ContextValue, OnBeforeHandler, SendbirdMessage, SendbirdChatSDK, SendbirdChannel, SendbirdBaseChannel, SendbirdGroupChannel, SendbirdOpenChannel, SendbirdUser, SendbirdMember, SendbirdBaseMessage, SendbirdUserMessage, SendbirdFileMessage, SendbirdAdminMessage, SendbirdGroupChannelCreateParams, SendbirdFileMessageCreateParams, SendbirdUserMessageCreateParams, SendbirdError, SendbirdMessageCollection, SendbirdGroupChannelCollection, NotificationFiles, NotificationMentionedUsers, NotificationTranslations, PartialNullable, SendbirdDataPayload, SendbirdPreviousMessageListQuery, SendbirdSendableMessage, SendbirdOpenChannelListQuery, SendbirdGroupChannelListQuery, SendbirdGroupChannelUpdateParams, SendbirdUserMessageUpdateParams, SendbirdFileMessageUpdateParams, SendbirdUserUpdateParams, SendbirdRestrictedUser, SendbirdReaction, SendbirdEmojiContainer, SendbirdEmoji, SendbirdEmojiCategory, SendbirdOpenChannelUpdateParams, SendbirdOpenChannelCreateParams, SendbirdParticipant, } from './types';
32
+ export * from './types';
@@ -1,4 +1,5 @@
1
- import type { SendbirdBaseChannel, SendbirdBaseMessage, SendbirdDataPayload, SendbirdFileMessage, SendbirdMessage, SendbirdReaction, SendbirdSendableMessage } from '../types';
1
+ import { MessageSearchOrder } from '@sendbird/chat/message';
2
+ import type { SendbirdBaseChannel, SendbirdBaseMessage, SendbirdDataPayload, SendbirdFileMessage, SendbirdGroupChannel, SendbirdMessage, SendbirdReaction, SendbirdSendableMessage } from '../types';
2
3
  export declare function isNewMessage(msg: SendbirdMessage, currentUserId?: string): boolean;
3
4
  export declare function isSendableMessage(msg?: SendbirdMessage | null): msg is SendbirdSendableMessage;
4
5
  export declare function isMyMessage(msg?: SendbirdMessage | null, currentUserId?: string): boolean;
@@ -23,4 +24,10 @@ export declare function getReactionCount(reaction: SendbirdReaction): number;
23
24
  type MessageType = 'user' | 'admin' | 'file' | 'unknown' | `user.${'opengraph'}` | `file.${'image' | 'video' | 'audio'}`;
24
25
  export declare function getFileTypeFromMessage(message: SendbirdFileMessage): "video" | "audio" | "image" | "file";
25
26
  export declare function getMessageType(message: SendbirdMessage): MessageType;
27
+ export declare function getDefaultMessageSearchQueryParams(channel: SendbirdGroupChannel, keyword: string): {
28
+ keyword: string;
29
+ channelUrl: string;
30
+ messageTimestampFrom: number;
31
+ order: MessageSearchOrder;
32
+ };
26
33
  export {};
@@ -3,7 +3,7 @@ import type SendbirdChat from '@sendbird/chat';
3
3
  import type { BaseChannel, Emoji, EmojiCategory, EmojiContainer, Participant, RestrictedUser, SendbirdError as SBError, User, UserUpdateParams } from '@sendbird/chat';
4
4
  import type { GroupChannel, GroupChannelCollection, GroupChannelCreateParams, GroupChannelListQuery, GroupChannelModule, GroupChannelUpdateParams, Member, MessageCollection } from '@sendbird/chat/groupChannel';
5
5
  import type { ModuleNamespaces, OpenChannelCreateParams, OpenChannelUpdateParams, SendableMessage } from '@sendbird/chat/lib/__definition';
6
- import type { AdminMessage, BaseMessage, FileMessage, FileMessageCreateParams, FileMessageUpdateParams, PreviousMessageListQuery, Reaction, UserMessage, UserMessageCreateParams, UserMessageUpdateParams } from '@sendbird/chat/message';
6
+ import type { AdminMessage, BaseMessage, FileMessage, FileMessageCreateParams, FileMessageUpdateParams, MessageSearchQuery, PreviousMessageListQuery, Reaction, UserMessage, UserMessageCreateParams, UserMessageUpdateParams } from '@sendbird/chat/message';
7
7
  import type { OpenChannel, OpenChannelListQuery, OpenChannelModule } from '@sendbird/chat/openChannel';
8
8
  export type FilterByValueType<T extends object, Type> = {
9
9
  [K in keyof T as T[K] extends Type ? K : never]: T[K];
@@ -55,6 +55,7 @@ export type SendbirdGroupChannelListQuery = GroupChannelListQuery;
55
55
  export type SendbirdOpenChannelListQuery = OpenChannelListQuery;
56
56
  export type SendbirdMessageCollection = MessageCollection;
57
57
  export type SendbirdPreviousMessageListQuery = PreviousMessageListQuery;
58
+ export type SendbirdMessageSearchQuery = MessageSearchQuery;
58
59
  export type SendbirdError = SBError;
59
60
  export interface SendbirdDataPayload {
60
61
  app_id: string;
@@ -1,4 +1,5 @@
1
1
  import type { Locale } from 'date-fns';
2
+ import type { SendbirdBaseMessage } from '../types';
2
3
  type TruncateMode = 'head' | 'mid' | 'tail';
3
4
  type TruncateOption = {
4
5
  mode: TruncateMode;
@@ -41,4 +42,16 @@ export declare const getDateSeparatorFormat: (date: Date, locale?: Locale) => st
41
42
  * @returns {string}
42
43
  * */
43
44
  export declare const getMessageTimeFormat: (date: Date, locale?: Locale) => string;
45
+ /**
46
+ * Message preview title text
47
+ * */
48
+ export declare const getMessagePreviewTitle: (message: SendbirdBaseMessage, EMPTY_USERNAME?: string) => string;
49
+ /**
50
+ * Message preview body text
51
+ * */
52
+ export declare const getMessagePreviewBody: (message: SendbirdBaseMessage, EMPTY_MESSAGE?: string) => string;
53
+ /**
54
+ * Message preview time format
55
+ * */
56
+ export declare const getMessagePreviewTime: (timestamp: number, locale?: Locale) => string;
44
57
  export {};
@@ -2,4 +2,4 @@ import type { Locale } from 'date-fns';
2
2
  import type { SendbirdGroupChannel } from '../types';
3
3
  export declare const getGroupChannelTitle: (currentUserId: string, channel: SendbirdGroupChannel, EMPTY_USERNAME?: string, NO_MEMBERS?: string, DEFAULT_CHANNEL_NAME?: string) => string;
4
4
  export declare const getGroupChannelPreviewTime: (channel: SendbirdGroupChannel, locale?: Locale) => string;
5
- export declare const getGroupChannelLastMessage: (channel: SendbirdGroupChannel, EMPTY_MESSAGE?: string, MAX_LEN?: number) => string;
5
+ export declare const getGroupChannelLastMessage: (channel: SendbirdGroupChannel, EMPTY_MESSAGE?: string) => string;
package/package.json CHANGED
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "@sendbird/uikit-utils",
3
- "version": "2.4.1",
4
- "description": "UIKit utilities",
3
+ "version": "2.5.0-rc.0",
4
+ "description": "A collection of utility functions and constants for building chat UI components with Sendbird UIKit.",
5
+ "keywords": [
6
+ "sendbird",
7
+ "uikit",
8
+ "chat",
9
+ "UI components",
10
+ "utility functions",
11
+ "constants"
12
+ ],
5
13
  "main": "lib/commonjs/index",
6
14
  "module": "lib/module/index",
7
15
  "types": "lib/typescript/src/index.d.ts",
@@ -18,10 +26,6 @@
18
26
  "build": "bob build",
19
27
  "clean": "del lib"
20
28
  },
21
- "keywords": [
22
- "react",
23
- "sendbird"
24
- ],
25
29
  "repository": {
26
30
  "type": "git",
27
31
  "url": "https://github.com/sendbird/sendbird-uikit-react-native.git",
@@ -76,6 +80,5 @@
76
80
  "entryPoint": "./src/index.ts",
77
81
  "readmeFile": "./README.md",
78
82
  "displayName": "@sendbird/uikit-utils"
79
- },
80
- "gitHead": "9ba7a005c941a3edd5b0f78d88d8cd1df6c280fc"
83
+ }
81
84
  }
@@ -102,3 +102,13 @@ export const useDebounceEffect = (action: () => void, delay: number, deps: Depen
102
102
  export const usePartialState = <S>(initialState: S) => {
103
103
  return useReducer((prev: S, state: Partial<S>) => ({ ...prev, ...state }), initialState);
104
104
  };
105
+
106
+ export const useRefTracker = <T>(target: T) => {
107
+ const ref = useRef(target);
108
+
109
+ useLayoutEffect(() => {
110
+ ref.current = target;
111
+ });
112
+
113
+ return ref;
114
+ };
package/src/index.ts CHANGED
@@ -29,9 +29,10 @@ export function ifThenOr(cond: boolean, then: unknown, or?: unknown) {
29
29
  }
30
30
 
31
31
  export const SBErrorCode = {
32
- NON_AUTHORIZED: 400108,
33
- CHANNEL_NOT_FOUND_SERVER: 400201,
34
- CHANNEL_NOT_FOUND_SDK: 900500,
32
+ UNAUTHORIZED_REQUEST: 400108,
33
+ RESOURCE_NOT_FOUND: 400201,
34
+ BANNED_USER_SEND_MESSAGE_NOT_ALLOWED: 900100,
35
+ CHANNEL_NOT_FOUND: 900500,
35
36
  };
36
37
  export const SBErrorMessage = {
37
38
  ACL:
@@ -41,52 +42,4 @@ export const SBErrorMessage = {
41
42
  'To manage your access control settings, you can turn on or off each setting on Sendbird Dashboard.',
42
43
  };
43
44
 
44
- export type {
45
- UserStruct,
46
- FilterByValueType,
47
- UnionToIntersection,
48
- OmittedValues,
49
- PartialDeep,
50
- Optional,
51
- ContextValue,
52
- OnBeforeHandler,
53
- SendbirdMessage,
54
- SendbirdChatSDK,
55
- SendbirdChannel,
56
- SendbirdBaseChannel,
57
- SendbirdGroupChannel,
58
- SendbirdOpenChannel,
59
- SendbirdUser,
60
- SendbirdMember,
61
- SendbirdBaseMessage,
62
- SendbirdUserMessage,
63
- SendbirdFileMessage,
64
- SendbirdAdminMessage,
65
- SendbirdGroupChannelCreateParams,
66
- SendbirdFileMessageCreateParams,
67
- SendbirdUserMessageCreateParams,
68
- SendbirdError,
69
- SendbirdMessageCollection,
70
- SendbirdGroupChannelCollection,
71
- NotificationFiles,
72
- NotificationMentionedUsers,
73
- NotificationTranslations,
74
- PartialNullable,
75
- SendbirdDataPayload,
76
- SendbirdPreviousMessageListQuery,
77
- SendbirdSendableMessage,
78
- SendbirdOpenChannelListQuery,
79
- SendbirdGroupChannelListQuery,
80
- SendbirdGroupChannelUpdateParams,
81
- SendbirdUserMessageUpdateParams,
82
- SendbirdFileMessageUpdateParams,
83
- SendbirdUserUpdateParams,
84
- SendbirdRestrictedUser,
85
- SendbirdReaction,
86
- SendbirdEmojiContainer,
87
- SendbirdEmoji,
88
- SendbirdEmojiCategory,
89
- SendbirdOpenChannelUpdateParams,
90
- SendbirdOpenChannelCreateParams,
91
- SendbirdParticipant,
92
- } from './types';
45
+ export * from './types';
@@ -1,9 +1,12 @@
1
+ import { MessageSearchOrder } from '@sendbird/chat/message';
2
+
1
3
  import { getFileExtension, getFileType } from '../shared/file';
2
4
  import type {
3
5
  SendbirdBaseChannel,
4
6
  SendbirdBaseMessage,
5
7
  SendbirdDataPayload,
6
8
  SendbirdFileMessage,
9
+ SendbirdGroupChannel,
7
10
  SendbirdMessage,
8
11
  SendbirdReaction,
9
12
  SendbirdSendableMessage,
@@ -173,3 +176,12 @@ export function getMessageType(message: SendbirdMessage): MessageType {
173
176
 
174
177
  return 'unknown';
175
178
  }
179
+
180
+ export function getDefaultMessageSearchQueryParams(channel: SendbirdGroupChannel, keyword: string) {
181
+ return {
182
+ keyword,
183
+ channelUrl: channel.url,
184
+ messageTimestampFrom: Math.max(channel.joinedAt, channel.invitedAt),
185
+ order: MessageSearchOrder.TIMESTAMP,
186
+ };
187
+ }
package/src/types.ts CHANGED
@@ -37,6 +37,7 @@ import type {
37
37
  FileMessage,
38
38
  FileMessageCreateParams,
39
39
  FileMessageUpdateParams,
40
+ MessageSearchQuery,
40
41
  PreviousMessageListQuery,
41
42
  Reaction,
42
43
  UserMessage,
@@ -115,6 +116,7 @@ export type SendbirdGroupChannelListQuery = GroupChannelListQuery;
115
116
  export type SendbirdOpenChannelListQuery = OpenChannelListQuery;
116
117
  export type SendbirdMessageCollection = MessageCollection;
117
118
  export type SendbirdPreviousMessageListQuery = PreviousMessageListQuery;
119
+ export type SendbirdMessageSearchQuery = MessageSearchQuery;
118
120
 
119
121
  export type SendbirdError = SBError;
120
122
 
@@ -1,5 +1,7 @@
1
1
  import type { Locale } from 'date-fns';
2
- import { format, isThisYear } from 'date-fns';
2
+ import { format, isThisYear, isToday, isYesterday } from 'date-fns';
3
+
4
+ import type { SendbirdBaseMessage } from '../types';
3
5
 
4
6
  type TruncateMode = 'head' | 'mid' | 'tail';
5
7
  type TruncateOption = { mode: TruncateMode; maxLen: number; separator: string };
@@ -73,3 +75,53 @@ export const getDateSeparatorFormat = (date: Date, locale?: Locale): string => {
73
75
  export const getMessageTimeFormat = (date: Date, locale?: Locale): string => {
74
76
  return format(date, 'p', { locale });
75
77
  };
78
+
79
+ /**
80
+ * Message preview title text
81
+ * */
82
+ export const getMessagePreviewTitle = (message: SendbirdBaseMessage, EMPTY_USERNAME = '(No name)') => {
83
+ if (message.isFileMessage() || message.isUserMessage()) {
84
+ return message.sender.nickname || EMPTY_USERNAME;
85
+ }
86
+ if (message.isAdminMessage()) {
87
+ return 'Admin';
88
+ }
89
+ return EMPTY_USERNAME;
90
+ };
91
+
92
+ /**
93
+ * Message preview body text
94
+ * */
95
+ export const getMessagePreviewBody = (message: SendbirdBaseMessage, EMPTY_MESSAGE = '') => {
96
+ if (message.isFileMessage()) {
97
+ const extIdx = message.name.lastIndexOf('.');
98
+ if (extIdx > -1) {
99
+ const file = message.name.slice(0, extIdx);
100
+ const ext = message.name.slice(extIdx);
101
+ return file + ext;
102
+ }
103
+
104
+ return message.name;
105
+ }
106
+
107
+ if (message.isUserMessage()) {
108
+ return message.message ?? EMPTY_MESSAGE;
109
+ }
110
+
111
+ if (message.isAdminMessage()) {
112
+ return message.message ?? EMPTY_MESSAGE;
113
+ }
114
+
115
+ return EMPTY_MESSAGE;
116
+ };
117
+
118
+ /**
119
+ * Message preview time format
120
+ * */
121
+ export const getMessagePreviewTime = (timestamp: number, locale?: Locale) => {
122
+ if (isToday(timestamp)) return format(timestamp, 'p', { locale });
123
+ if (isYesterday(timestamp)) return 'Yesterday';
124
+ if (isThisYear(timestamp)) return format(timestamp, 'MMM dd', { locale });
125
+
126
+ return format(timestamp, 'yyyy/MM/dd', { locale });
127
+ };
@@ -1,8 +1,7 @@
1
1
  import type { Locale } from 'date-fns';
2
- import { format, isThisYear, isToday, isYesterday } from 'date-fns';
3
2
 
4
3
  import type { SendbirdGroupChannel } from '../types';
5
- import { truncate } from './common';
4
+ import { getMessagePreviewBody, getMessagePreviewTime } from './common';
6
5
 
7
6
  export const getGroupChannelTitle = (
8
7
  currentUserId: string,
@@ -20,37 +19,12 @@ export const getGroupChannelTitle = (
20
19
  };
21
20
 
22
21
  export const getGroupChannelPreviewTime = (channel: SendbirdGroupChannel, locale?: Locale) => {
23
- const timestamp = channel.lastMessage?.createdAt || channel.joinedAt * 1000 || channel.createdAt;
24
-
25
- if (isToday(timestamp)) return format(timestamp, 'p', { locale });
26
- if (isYesterday(timestamp)) return 'Yesterday';
27
- if (isThisYear(timestamp)) return format(timestamp, 'MMM dd', { locale });
28
-
29
- return format(timestamp, 'yyyy/MM/dd', { locale });
22
+ return getMessagePreviewTime(channel.lastMessage?.createdAt || channel.joinedAt * 1000 || channel.createdAt, locale);
30
23
  };
31
24
 
32
- export const getGroupChannelLastMessage = (channel: SendbirdGroupChannel, EMPTY_MESSAGE = '', MAX_LEN = 15) => {
25
+ export const getGroupChannelLastMessage = (channel: SendbirdGroupChannel, EMPTY_MESSAGE = '') => {
33
26
  const message = channel.lastMessage;
34
27
  if (!message) return EMPTY_MESSAGE;
35
28
 
36
- if (message.isFileMessage()) {
37
- const extIdx = message.name.lastIndexOf('.');
38
- if (extIdx > -1) {
39
- const file = message.name.slice(0, extIdx);
40
- const ext = message.name.slice(extIdx);
41
- return truncate(file, { maxLen: MAX_LEN }) + ext;
42
- }
43
-
44
- return truncate(message.name, { maxLen: MAX_LEN });
45
- }
46
-
47
- if (message.isUserMessage()) {
48
- return message.message ?? EMPTY_MESSAGE;
49
- }
50
-
51
- if (message.isAdminMessage()) {
52
- return message.message ?? EMPTY_MESSAGE;
53
- }
54
-
55
- return EMPTY_MESSAGE;
29
+ return getMessagePreviewBody(message, EMPTY_MESSAGE);
56
30
  };