@sendbird/ai-agent-messenger-react-native 0.0.1-beta.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.
- package/LICENSE +35 -0
- package/README.md +3 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +952 -0
- package/dist/index.js +5029 -0
- package/package.json +112 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,952 @@
|
|
|
1
|
+
import { AIAgentChannelFilter } from '@sendbird/chat/aiAgent';
|
|
2
|
+
import { AIAgentModule } from '@sendbird/chat/aiAgent';
|
|
3
|
+
import { BaseMessage } from '@sendbird/chat/message';
|
|
4
|
+
import type * as CommunityDocumentPicker from '@react-native-documents/picker';
|
|
5
|
+
import type * as CommunityImagePicker from 'react-native-image-picker';
|
|
6
|
+
import { ComponentType } from 'react';
|
|
7
|
+
import { Context } from 'react';
|
|
8
|
+
import { Conversation as Conversation_2 } from '@sendbird/chat/aiAgent';
|
|
9
|
+
import { ConversationStatus } from '@sendbird/chat/aiAgent';
|
|
10
|
+
import { DeskChannelFilter } from '@sendbird/chat/aiAgent';
|
|
11
|
+
import type * as ExpoDocumentPicker from 'expo-document-picker';
|
|
12
|
+
import type * as ExpoImagePicker from 'expo-image-picker';
|
|
13
|
+
import { FileMessage } from '@sendbird/chat/message';
|
|
14
|
+
import { FileMessageCreateParams } from '@sendbird/chat/message';
|
|
15
|
+
import { FlatList } from 'react-native';
|
|
16
|
+
import { FlatListProps } from 'react-native';
|
|
17
|
+
import { ForwardRefExoticComponent } from 'react';
|
|
18
|
+
import { GroupChannel } from '@sendbird/chat/groupChannel';
|
|
19
|
+
import { GroupChannelModule } from '@sendbird/chat/groupChannel';
|
|
20
|
+
import { JSX } from 'react/jsx-runtime';
|
|
21
|
+
import { LayoutChangeEvent } from 'react-native';
|
|
22
|
+
import { LogLevel } from '@sendbird/chat';
|
|
23
|
+
import { MMKV } from 'react-native-mmkv';
|
|
24
|
+
import { NativeScrollEvent } from 'react-native';
|
|
25
|
+
import { NativeSyntheticEvent } from 'react-native';
|
|
26
|
+
import { PropsWithChildren } from 'react';
|
|
27
|
+
import { ReactNode } from 'react';
|
|
28
|
+
import { RefAttributes } from 'react';
|
|
29
|
+
import { RefObject } from 'react';
|
|
30
|
+
import { SendbirdChatParams } from '@sendbird/chat';
|
|
31
|
+
import { SendbirdChatWith } from '@sendbird/chat';
|
|
32
|
+
import { SendbirdError } from '@sendbird/chat';
|
|
33
|
+
import { SessionHandler } from '@sendbird/chat';
|
|
34
|
+
import { User } from '@sendbird/chat';
|
|
35
|
+
import { UserMessage } from '@sendbird/chat/message';
|
|
36
|
+
import { UserMessageCreateParams } from '@sendbird/chat/message';
|
|
37
|
+
|
|
38
|
+
declare interface AIAgentCache {
|
|
39
|
+
template: MessageTemplateCache;
|
|
40
|
+
messenger: MessengerSessionCache;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
declare interface AIAgentConfig {
|
|
44
|
+
conversation?: {
|
|
45
|
+
isTalkToAgentViewEnabled?: boolean;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
declare interface AIAgentContextValue {
|
|
50
|
+
appId: string;
|
|
51
|
+
aiAgentId: string;
|
|
52
|
+
chatSDK: SendbirdChatWith<[GroupChannelModule, AIAgentModule]>;
|
|
53
|
+
|
|
54
|
+
language: string;
|
|
55
|
+
countryCode?: string;
|
|
56
|
+
context?: Record<string, string>;
|
|
57
|
+
|
|
58
|
+
logger: Loggable;
|
|
59
|
+
dispatcher: Dispatcher;
|
|
60
|
+
|
|
61
|
+
cache: AIAgentCache;
|
|
62
|
+
|
|
63
|
+
queryParams?: AIAgentQueryParams;
|
|
64
|
+
config?: AIAgentConfig;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
declare interface AIAgentConversationContextValue {
|
|
68
|
+
conversation: Conversation_2 | undefined;
|
|
69
|
+
|
|
70
|
+
channelSource: {
|
|
71
|
+
channel: GroupChannel | undefined;
|
|
72
|
+
error: SendbirdError | undefined;
|
|
73
|
+
refetch: () => Promise<void>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
messageSource: {
|
|
77
|
+
messages: BaseMessage[];
|
|
78
|
+
initialized: boolean;
|
|
79
|
+
loadPrevious: () => Promise<void>;
|
|
80
|
+
loadNext: () => Promise<void>;
|
|
81
|
+
sendUserMessage: (params: UserMessageCreateParams) => Promise<UserMessage>;
|
|
82
|
+
sendFileMessage: (params: FileMessageCreateParams) => Promise<FileMessage>;
|
|
83
|
+
deleteMessage: (message: UserMessage | FileMessage) => Promise<void>;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
state: {
|
|
87
|
+
input: InputState;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
declare interface AIAgentConversationListContextValue {
|
|
92
|
+
listSource: {
|
|
93
|
+
initialized: boolean;
|
|
94
|
+
error: SendbirdError | undefined;
|
|
95
|
+
channels: GroupChannel[];
|
|
96
|
+
loadMore: () => Promise<void>;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
declare interface AIAgentGroupChannelFilter {
|
|
101
|
+
/**
|
|
102
|
+
* The filter applied to AI agent channels.
|
|
103
|
+
* It determines whether to include or exclude AI agent channels in the query results.
|
|
104
|
+
*/
|
|
105
|
+
aiAgentChannelFilter?: AIAgentChannelFilter;
|
|
106
|
+
/**
|
|
107
|
+
* The filter applied to AI agent conversation statuses.
|
|
108
|
+
* It allows filtering channels based on the status of their conversations.
|
|
109
|
+
*/
|
|
110
|
+
aiAgentConversationStatusFilter?: ConversationStatus[];
|
|
111
|
+
/**
|
|
112
|
+
* The list of AI agent IDs to filter the channels.
|
|
113
|
+
* Only channels associated with these AI agents will be included in the results.
|
|
114
|
+
*/
|
|
115
|
+
aiAgentIds?: string[];
|
|
116
|
+
/**
|
|
117
|
+
* The filter applied to Desk channels.
|
|
118
|
+
* It determines whether to include or exclude Desk channels in the query results.
|
|
119
|
+
*/
|
|
120
|
+
deskChannelFilter?: DeskChannelFilter;
|
|
121
|
+
/**
|
|
122
|
+
* The list of pinned channel URLs.
|
|
123
|
+
* These channels are prioritized in the query results.
|
|
124
|
+
*/
|
|
125
|
+
pinnedChannelUrls?: string[];
|
|
126
|
+
/**
|
|
127
|
+
* The filter applied to copilot conversation only channels.
|
|
128
|
+
* It determines whether to include only copilot conversation channels.
|
|
129
|
+
*/
|
|
130
|
+
copilotConversationOnly?: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* The copilot support channel URL.
|
|
133
|
+
* This channel is used for copilot support conversations.
|
|
134
|
+
*/
|
|
135
|
+
copilotSupportChannelUrl?: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
declare interface AIAgentInfo {
|
|
139
|
+
userId: string;
|
|
140
|
+
nickname: string;
|
|
141
|
+
profileUrl: string;
|
|
142
|
+
replyToFile: boolean;
|
|
143
|
+
showHandoffButton: boolean;
|
|
144
|
+
specialNotice: string;
|
|
145
|
+
specialNoticeEnabled: boolean;
|
|
146
|
+
isMultipleActiveConversationsEnabled: boolean;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
declare interface AIAgentMessengerSessionContextValue {
|
|
150
|
+
userSessionInfo?: UserSessionInfo | ManualSessionInfo | AnonymousSessionInfo;
|
|
151
|
+
|
|
152
|
+
sdkUser: null | User;
|
|
153
|
+
userSession: null | UserSession;
|
|
154
|
+
aiAgentInfo: null | AIAgentInfo;
|
|
155
|
+
launcherInfo: null | LauncherInfo;
|
|
156
|
+
attachmentMode: AttachmentMode;
|
|
157
|
+
|
|
158
|
+
connectionError?: Error;
|
|
159
|
+
|
|
160
|
+
activeChannel?: { url: string; status: ConversationStatus };
|
|
161
|
+
setActiveChannel: (param: { url: string; status: ConversationStatus }) => void;
|
|
162
|
+
|
|
163
|
+
createConversation: (params: ConversationCreateParams) => Promise<string>;
|
|
164
|
+
refreshActiveChannel: () => Promise<string>;
|
|
165
|
+
|
|
166
|
+
authenticate: () => Promise<MessengerSettingsResponse>;
|
|
167
|
+
deauthenticate: () => Promise<void>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
declare interface AIAgentMessengerSessionRef {
|
|
171
|
+
activeChannel?: { url: string; status: ConversationStatus };
|
|
172
|
+
chatSDK: AIAgentContextValue['chatSDK'];
|
|
173
|
+
authenticate: () => Promise<MessengerSettingsResponse>;
|
|
174
|
+
deauthenticate: () => Promise<void>;
|
|
175
|
+
updateContext: (context: Record<string, string>) => Promise<ContextObject>;
|
|
176
|
+
patchContext: (context: Record<string, string>) => Promise<ContextObject>;
|
|
177
|
+
getContextObject: () => Promise<ContextObject>;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export declare const AIAgentProviderContainer: ForwardRefExoticComponent< {
|
|
181
|
+
appId: string;
|
|
182
|
+
aiAgentId: string;
|
|
183
|
+
/**
|
|
184
|
+
* @public
|
|
185
|
+
* @description Native modules configuration (includes imagePicker, documentPicker, and mmkv)
|
|
186
|
+
* */
|
|
187
|
+
nativeModules: NativeAdapterConfig;
|
|
188
|
+
/**
|
|
189
|
+
* @public
|
|
190
|
+
* @description Inject a custom Chat SDK. GroupChannelModule and AIAgentModule must be included in the initialization.
|
|
191
|
+
* */
|
|
192
|
+
customChatSDK?: SendbirdChatWith<[GroupChannelModule, AIAgentModule]>;
|
|
193
|
+
/**
|
|
194
|
+
* @public
|
|
195
|
+
* @description Custom parameters for initializing the chat SDK.
|
|
196
|
+
* */
|
|
197
|
+
chatParams?: Partial<SendbirdChatParams<[GroupChannelModule, AIAgentModule]>>;
|
|
198
|
+
/**
|
|
199
|
+
* @public
|
|
200
|
+
* @description AIAgent Messenger theme
|
|
201
|
+
* */
|
|
202
|
+
theme?: {
|
|
203
|
+
mode?: "light" | "dark";
|
|
204
|
+
palette?: Partial<PaletteShape>;
|
|
205
|
+
typography?: Partial<{ [K in keyof TypographyShape]: Partial<TypographyShape[K]>; }>;
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* @public
|
|
209
|
+
* @description Custom User session information to be used in connecting to the agent.
|
|
210
|
+
* */
|
|
211
|
+
userSessionInfo: ManualSessionInfo | AnonymousSessionInfo;
|
|
212
|
+
/**
|
|
213
|
+
* @public
|
|
214
|
+
* @description logLevel for the ai agent client.
|
|
215
|
+
* */
|
|
216
|
+
logLevel?: LogLevel;
|
|
217
|
+
/**
|
|
218
|
+
* @public
|
|
219
|
+
* @description Language for the ai agent client. Should follow the IETF BCP 47 format.
|
|
220
|
+
* For example, "ko-KR" for Korean in South Korea or "en-US" for English in the United States.
|
|
221
|
+
* */
|
|
222
|
+
language?: string;
|
|
223
|
+
/**
|
|
224
|
+
* @public
|
|
225
|
+
* @description Localization string set for the ai agent client.
|
|
226
|
+
* */
|
|
227
|
+
strings?: PartialDeep<StringSet>;
|
|
228
|
+
/**
|
|
229
|
+
* @public
|
|
230
|
+
* @description Country code for the ai agent client. Should follow the ISO 3166 format.
|
|
231
|
+
* For example, "KR" for South Korea or "US" for the United States.
|
|
232
|
+
* */
|
|
233
|
+
countryCode?: string;
|
|
234
|
+
/**
|
|
235
|
+
* @public
|
|
236
|
+
* @description Context object for the AI agent client. This is injected when the messenger is first loaded and can provide additional context that may influence how the AI responds to user conversations.
|
|
237
|
+
* */
|
|
238
|
+
context?: Record<string, string>;
|
|
239
|
+
/**
|
|
240
|
+
* @public
|
|
241
|
+
* @description AIAgent global default query parameters.
|
|
242
|
+
* */
|
|
243
|
+
queryParams?: AIAgentQueryParams;
|
|
244
|
+
/**
|
|
245
|
+
* @public
|
|
246
|
+
* @description AIAgent global default config.
|
|
247
|
+
* */
|
|
248
|
+
config?: AIAgentConfig;
|
|
249
|
+
} & {
|
|
250
|
+
children?: ReactNode | undefined;
|
|
251
|
+
} & RefAttributes<AIAgentMessengerSessionRef>>;
|
|
252
|
+
|
|
253
|
+
declare interface AIAgentQueryParams {
|
|
254
|
+
conversationListParams?: ConversationListCollectionParams;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Common string set interface shared between react and react-native packages
|
|
259
|
+
* These are the base strings that both packages use
|
|
260
|
+
* Structure follows the react-native nested format
|
|
261
|
+
*/
|
|
262
|
+
declare interface AIAgentStringSet {
|
|
263
|
+
conversation: {
|
|
264
|
+
input_placeholder: string;
|
|
265
|
+
input_placeholder_disabled: string;
|
|
266
|
+
input_placeholder_wait_ai_agent_response: string;
|
|
267
|
+
input_placeholder_active_form: string;
|
|
268
|
+
|
|
269
|
+
unknown_message_type: string;
|
|
270
|
+
powered_by: string;
|
|
271
|
+
citation_title: string;
|
|
272
|
+
start_new_conversation_label: string;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
conversation_list: {
|
|
276
|
+
header_title: string;
|
|
277
|
+
ended: string;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
date_format: {
|
|
281
|
+
just_now: string;
|
|
282
|
+
minutes_ago: (minutes: number) => string;
|
|
283
|
+
hours_ago: (hours: number) => string;
|
|
284
|
+
date_short: string;
|
|
285
|
+
date_separator: string;
|
|
286
|
+
message_timestamp: string;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
csat: {
|
|
290
|
+
title: string;
|
|
291
|
+
submitted_label: string;
|
|
292
|
+
cre_question: string;
|
|
293
|
+
cre_positive_label: string;
|
|
294
|
+
cre_negative_label: string;
|
|
295
|
+
reason_placeholder: string;
|
|
296
|
+
question: string;
|
|
297
|
+
submit_label: string;
|
|
298
|
+
submission_expired: string;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
form: {
|
|
302
|
+
optional_label: string;
|
|
303
|
+
validation_required: string;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
common: {
|
|
307
|
+
placeholder_something_went_wrong: string;
|
|
308
|
+
placeholder_no_messages: string;
|
|
309
|
+
placeholder_no_conversations: string;
|
|
310
|
+
placeholder_something_went_wrong_retry_label: string;
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
declare type AnonUserSessionData = { userId: string; authToken: string; expireAt: number };
|
|
315
|
+
|
|
316
|
+
export declare class AnonymousSessionInfo {
|
|
317
|
+
userId?: never;
|
|
318
|
+
authToken?: never;
|
|
319
|
+
sessionHandler?: never;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
declare enum AttachmentMode {
|
|
323
|
+
OFF = 'off',
|
|
324
|
+
ALWAYS = 'always',
|
|
325
|
+
HANDED_OFF_ONLY = 'handed_off_only',
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
declare abstract class BaseCommand {
|
|
329
|
+
abstract type: CommandType;
|
|
330
|
+
payload: any;
|
|
331
|
+
|
|
332
|
+
constructor(payload: any = {}) {
|
|
333
|
+
this.payload = payload;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
toJSON(): string {
|
|
337
|
+
return JSON.stringify({ type: this.type, payload: this.payload });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export declare const BottomSheet: {
|
|
342
|
+
(props: BottomSheetTemplateProps): JSX.Element;
|
|
343
|
+
ActionItem(props: BottomSheetActionItemProps): ReactNode;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
declare interface BottomSheetActionItemProps extends BottomSheetTemplateProps {
|
|
347
|
+
icon?: IconType;
|
|
348
|
+
label?: string;
|
|
349
|
+
destructive?: boolean;
|
|
350
|
+
onPress?: () => void;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export declare const BottomSheetLayout: {
|
|
354
|
+
(props: PropsWithChildren): ReactNode;
|
|
355
|
+
defaults: {
|
|
356
|
+
template: ComponentType<BottomSheetTemplateProps>;
|
|
357
|
+
components: {
|
|
358
|
+
ActionItem: ({ icon, label, destructive, onPress, }: BottomSheetActionItemProps) => ReactNode;
|
|
359
|
+
};
|
|
360
|
+
};
|
|
361
|
+
Template: ({ template, children }: {
|
|
362
|
+
template?: ComponentType<BottomSheetTemplateProps> | undefined;
|
|
363
|
+
children?: ReactNode;
|
|
364
|
+
}) => JSX.Element;
|
|
365
|
+
Context: Context<LayoutContextValue< {
|
|
366
|
+
ActionItem: ({ icon, label, destructive, onPress, }: BottomSheetActionItemProps) => ReactNode;
|
|
367
|
+
}, BottomSheetTemplateProps>>;
|
|
368
|
+
useContext: () => LayoutContextValue< {
|
|
369
|
+
ActionItem: ({ icon, label, destructive, onPress, }: BottomSheetActionItemProps) => ReactNode;
|
|
370
|
+
}, BottomSheetTemplateProps>;
|
|
371
|
+
} & {
|
|
372
|
+
ActionItem: (props: {
|
|
373
|
+
component: ({ icon, label, destructive, onPress, }: BottomSheetActionItemProps) => ReactNode;
|
|
374
|
+
}) => null;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
declare interface BottomSheetTemplateProps {
|
|
378
|
+
onClose?: () => void;
|
|
379
|
+
children?: ReactNode;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
declare interface CloseConversationCommandParams {
|
|
383
|
+
channelUrl: string;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
declare interface CommandPayloads {
|
|
387
|
+
[CommandType.ConversationClose]: undefined | CloseConversationCommandParams;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
declare enum CommandType {
|
|
391
|
+
ConversationClose = 'conv.close',
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
declare type CommunityDocumentPickerModule = typeof CommunityDocumentPicker;
|
|
395
|
+
|
|
396
|
+
declare type CommunityImagePickerModule = typeof CommunityImagePicker;
|
|
397
|
+
|
|
398
|
+
declare interface ContextObject {
|
|
399
|
+
language?: string;
|
|
400
|
+
country?: string;
|
|
401
|
+
context: Record<string, string>;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export declare const Conversation: ({ children, ...props }: ConversationContextProps) => JSX.Element;
|
|
405
|
+
|
|
406
|
+
export declare const ConversationContext: Context<ConversationContextValue | null>;
|
|
407
|
+
|
|
408
|
+
declare interface ConversationContextProps extends PropsWithChildren {
|
|
409
|
+
channelUrl?: string;
|
|
410
|
+
onClearChannelUrl?: () => void;
|
|
411
|
+
onNavigateToConversationList?: () => void;
|
|
412
|
+
onClose?: () => void;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export declare const ConversationContextProvider: ({ channelUrl, onClearChannelUrl, onClose, onNavigateToConversationList, children, }: ConversationContextProps) => JSX.Element;
|
|
416
|
+
|
|
417
|
+
declare interface ConversationContextValue extends AIAgentConversationContextValue {
|
|
418
|
+
scrollSource: ConversationScrollContextValue;
|
|
419
|
+
updateActiveChannel: () => Promise<void>;
|
|
420
|
+
onNavigateToConversationList?: () => void;
|
|
421
|
+
onClose?: () => void;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
declare interface ConversationCreateParams {
|
|
425
|
+
aiAgentId: string;
|
|
426
|
+
language?: string;
|
|
427
|
+
country?: string;
|
|
428
|
+
context?: Record<string, string>;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export declare const ConversationLayout: {
|
|
432
|
+
(props: PropsWithChildren): ReactNode;
|
|
433
|
+
defaults: {
|
|
434
|
+
template: ComponentType< {}>;
|
|
435
|
+
components: {
|
|
436
|
+
Header: () => ReactNode;
|
|
437
|
+
Body: ({ messageStackDirection, }: {
|
|
438
|
+
messageStackDirection?: "top" | "bottom";
|
|
439
|
+
}) => ReactNode;
|
|
440
|
+
Footer: () => ReactNode;
|
|
441
|
+
};
|
|
442
|
+
};
|
|
443
|
+
Template: ({ template, children }: {
|
|
444
|
+
template?: ComponentType< {}> | undefined;
|
|
445
|
+
children?: ReactNode;
|
|
446
|
+
}) => JSX.Element;
|
|
447
|
+
Context: Context<LayoutContextValue< {
|
|
448
|
+
Header: () => ReactNode;
|
|
449
|
+
Body: ({ messageStackDirection, }: {
|
|
450
|
+
messageStackDirection?: "top" | "bottom";
|
|
451
|
+
}) => ReactNode;
|
|
452
|
+
Footer: () => ReactNode;
|
|
453
|
+
}, {}>>;
|
|
454
|
+
useContext: () => LayoutContextValue< {
|
|
455
|
+
Header: () => ReactNode;
|
|
456
|
+
Body: ({ messageStackDirection, }: {
|
|
457
|
+
messageStackDirection?: "top" | "bottom";
|
|
458
|
+
}) => ReactNode;
|
|
459
|
+
Footer: () => ReactNode;
|
|
460
|
+
}, {}>;
|
|
461
|
+
} & {
|
|
462
|
+
Header: (props: {
|
|
463
|
+
component: () => ReactNode;
|
|
464
|
+
}) => null;
|
|
465
|
+
Body: (props: {
|
|
466
|
+
component: ({ messageStackDirection, }: {
|
|
467
|
+
messageStackDirection?: "top" | "bottom";
|
|
468
|
+
}) => ReactNode;
|
|
469
|
+
}) => null;
|
|
470
|
+
Footer: (props: {
|
|
471
|
+
component: () => ReactNode;
|
|
472
|
+
}) => null;
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
export declare const ConversationList: ({ children, ...props }: ConversationListContextProps) => JSX.Element;
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Parameters for creating a ConversationListCollection instance.
|
|
479
|
+
*/
|
|
480
|
+
declare interface ConversationListCollectionParams {
|
|
481
|
+
/** Filter options for AI agent group channels */
|
|
482
|
+
filter?: AIAgentGroupChannelFilter;
|
|
483
|
+
/** Maximum number of channels to load per request (default: 20) */
|
|
484
|
+
limit?: number;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export declare const ConversationListContext: Context<ConversationListContextValue | null>;
|
|
488
|
+
|
|
489
|
+
declare interface ConversationListContextProps extends PropsWithChildren {
|
|
490
|
+
conversationListLimit?: number;
|
|
491
|
+
conversationListFilter?: Partial<AIAgentGroupChannelFilter>;
|
|
492
|
+
onNavigateToConversation?: (channelUrl: string, status: 'open' | 'closed') => void;
|
|
493
|
+
onClose?: () => void;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export declare const ConversationListContextProvider: ({ conversationListLimit, conversationListFilter, onNavigateToConversation, onClose, children, }: ConversationListContextProps) => JSX.Element;
|
|
497
|
+
|
|
498
|
+
declare interface ConversationListContextValue extends AIAgentConversationListContextValue {
|
|
499
|
+
onNavigateToConversation?: (channelUrl: string, status: 'open' | 'closed') => void;
|
|
500
|
+
onClose?: () => void;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export declare const ConversationListLayout: {
|
|
504
|
+
(props: PropsWithChildren): ReactNode;
|
|
505
|
+
defaults: {
|
|
506
|
+
template: ComponentType<unknown>;
|
|
507
|
+
components: {
|
|
508
|
+
Header: () => ReactNode;
|
|
509
|
+
Body: () => ReactNode;
|
|
510
|
+
Footer: () => ReactNode;
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
Template: ({ template, children }: {
|
|
514
|
+
template?: ComponentType<unknown> | undefined;
|
|
515
|
+
children?: ReactNode;
|
|
516
|
+
}) => JSX.Element;
|
|
517
|
+
Context: Context<LayoutContextValue< {
|
|
518
|
+
Header: () => ReactNode;
|
|
519
|
+
Body: () => ReactNode;
|
|
520
|
+
Footer: () => ReactNode;
|
|
521
|
+
}, unknown>>;
|
|
522
|
+
useContext: () => LayoutContextValue< {
|
|
523
|
+
Header: () => ReactNode;
|
|
524
|
+
Body: () => ReactNode;
|
|
525
|
+
Footer: () => ReactNode;
|
|
526
|
+
}, unknown>;
|
|
527
|
+
} & {
|
|
528
|
+
Header: (props: {
|
|
529
|
+
component: () => ReactNode;
|
|
530
|
+
}) => null;
|
|
531
|
+
Body: (props: {
|
|
532
|
+
component: () => ReactNode;
|
|
533
|
+
}) => null;
|
|
534
|
+
Footer: (props: {
|
|
535
|
+
component: () => ReactNode;
|
|
536
|
+
}) => null;
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
declare interface ConversationScrollContextValue {
|
|
540
|
+
ref: RefObject<FlatList | null>;
|
|
541
|
+
state: {
|
|
542
|
+
distanceFromBottom: number;
|
|
543
|
+
isAtBottom: boolean;
|
|
544
|
+
bottomSpace?: number;
|
|
545
|
+
};
|
|
546
|
+
props: {
|
|
547
|
+
maintainVisibleContentPosition: MaintainVisibleContentPosition | undefined;
|
|
548
|
+
onLayout?: (event: LayoutChangeEvent) => void;
|
|
549
|
+
onContentSizeChange?: (width: number, height: number) => void;
|
|
550
|
+
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
551
|
+
};
|
|
552
|
+
actions: {
|
|
553
|
+
/**
|
|
554
|
+
* Scrolls to the bottom of the list (latest messages in inverted list)
|
|
555
|
+
* @param animated - Whether to animate the scroll. Defaults to true
|
|
556
|
+
*/
|
|
557
|
+
scrollToBottom: (animated?: boolean) => void;
|
|
558
|
+
/**
|
|
559
|
+
* Scrolls to a specific item by index with the item positioned at the top of viewport
|
|
560
|
+
* @param index - The index of the item to scroll to
|
|
561
|
+
* @param animated - Whether to animate the scroll. Defaults to true
|
|
562
|
+
*/
|
|
563
|
+
scrollToIndex: (index: number, animated?: boolean) => void;
|
|
564
|
+
/**
|
|
565
|
+
* Call before sending a message
|
|
566
|
+
* - Fixed mode: Captures current content height as baseline for padding calculation
|
|
567
|
+
* - Auto mode: No operation
|
|
568
|
+
*/
|
|
569
|
+
onBeforeMessageSend: () => void;
|
|
570
|
+
/**
|
|
571
|
+
* Call after a message is sent and rendered
|
|
572
|
+
* - Fixed mode: Scrolls to index 0 to position the new message at viewport top
|
|
573
|
+
* - Auto mode: Scrolls to bottom to show the latest message
|
|
574
|
+
*/
|
|
575
|
+
onAfterMessageSend: () => void;
|
|
576
|
+
/**
|
|
577
|
+
* Call when receiving streaming message updates
|
|
578
|
+
* - Fixed mode: No operation (position maintained automatically via maintainVisibleContentPosition)
|
|
579
|
+
* - Auto mode: Continuously scrolls to bottom to track real-time updates
|
|
580
|
+
*/
|
|
581
|
+
onStreamingUpdate: () => void;
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
declare interface Dispatcher {
|
|
586
|
+
send(command: BaseCommand): Promise<void>;
|
|
587
|
+
subscribe<E extends CommandType>(eventType: E, callback: (payload: CommandPayloads[E]) => void | Promise<void>): void;
|
|
588
|
+
unsubscribe<E extends CommandType>(
|
|
589
|
+
eventType: E,
|
|
590
|
+
callback: (payload: CommandPayloads[E]) => void | Promise<void>,
|
|
591
|
+
): void;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
declare type ExpoDocumentPickerModule = typeof ExpoDocumentPicker;
|
|
595
|
+
|
|
596
|
+
declare type ExpoImagePickerModule = typeof ExpoImagePicker;
|
|
597
|
+
|
|
598
|
+
declare const icons: {
|
|
599
|
+
send: any;
|
|
600
|
+
close: any;
|
|
601
|
+
menu: any;
|
|
602
|
+
chat: any;
|
|
603
|
+
message: any;
|
|
604
|
+
spinner: any;
|
|
605
|
+
error: any;
|
|
606
|
+
refresh: any;
|
|
607
|
+
'chevron-down': any;
|
|
608
|
+
done: any;
|
|
609
|
+
'done-all': any;
|
|
610
|
+
user: any;
|
|
611
|
+
'file-document': any;
|
|
612
|
+
remove: any;
|
|
613
|
+
add: any;
|
|
614
|
+
agent: any;
|
|
615
|
+
camera: any;
|
|
616
|
+
photo: any;
|
|
617
|
+
document: any;
|
|
618
|
+
'bot-filled': any;
|
|
619
|
+
copy: any;
|
|
620
|
+
source: any;
|
|
621
|
+
'radio-on': any;
|
|
622
|
+
'radio-off': any;
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
declare type IconType = keyof typeof icons;
|
|
626
|
+
|
|
627
|
+
declare type InputState = {
|
|
628
|
+
disabled: boolean;
|
|
629
|
+
disabledBy:
|
|
630
|
+
| 'unavailable'
|
|
631
|
+
| 'form_active'
|
|
632
|
+
| 'ai_responding'
|
|
633
|
+
| 'conversation_closed'
|
|
634
|
+
| 'suggested_replies'
|
|
635
|
+
| (string & {});
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
declare interface KeyValueStorage {
|
|
639
|
+
get(key: string): null | string;
|
|
640
|
+
set(key: string, value: string): void;
|
|
641
|
+
delete(key: string): void;
|
|
642
|
+
getKeys(startsWith: string): string[];
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
declare type LauncherImageType = 'default_icon' | 'custom_image';
|
|
646
|
+
|
|
647
|
+
declare interface LauncherInfo {
|
|
648
|
+
type: LauncherImageType;
|
|
649
|
+
imageUrl: string;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
declare interface LayoutContextValue<Components extends Record<string, ComponentType<Props>>, Props> {
|
|
653
|
+
Template: ComponentType<Props>;
|
|
654
|
+
updateTemplate: (template: ComponentType<Props>) => void;
|
|
655
|
+
components: Components;
|
|
656
|
+
updateComponent: (key: keyof Components, component: Components[keyof Components]) => void;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
declare interface Loggable {
|
|
660
|
+
verbose(...args: any[]): void;
|
|
661
|
+
debug(...args: any[]): void;
|
|
662
|
+
info(...args: any[]): void;
|
|
663
|
+
warn(...args: any[]): void;
|
|
664
|
+
error(...args: any[]): void;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
declare type MaintainVisibleContentPosition = FlatListProps<any>['maintainVisibleContentPosition'];
|
|
668
|
+
|
|
669
|
+
export declare class ManualSessionInfo {
|
|
670
|
+
userId: string;
|
|
671
|
+
authToken: string;
|
|
672
|
+
sessionHandler: SessionHandler;
|
|
673
|
+
|
|
674
|
+
constructor({ userId, authToken, sessionHandler }: ManualSessionInfoParams) {
|
|
675
|
+
this.userId = userId;
|
|
676
|
+
this.authToken = authToken;
|
|
677
|
+
this.sessionHandler = sessionHandler;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
declare interface ManualSessionInfoParams {
|
|
682
|
+
userId: string;
|
|
683
|
+
authToken: string;
|
|
684
|
+
sessionHandler: SessionHandler;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/** File metadata returned from picker methods */
|
|
688
|
+
declare interface MediaFile {
|
|
689
|
+
uri: string;
|
|
690
|
+
type: string;
|
|
691
|
+
size: number;
|
|
692
|
+
name: string;
|
|
693
|
+
width?: number;
|
|
694
|
+
height?: number;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/** Picker options */
|
|
698
|
+
declare interface MediaPickerOptions {
|
|
699
|
+
/** Allow multiple file selection */
|
|
700
|
+
multiple?: boolean;
|
|
701
|
+
/** Filter by MIME types (e.g., ['image/jpeg', 'image/png', 'application/pdf']) */
|
|
702
|
+
mimeTypes?: string[];
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
declare interface MessageTemplateCache {
|
|
706
|
+
set(key: string, value: string): void;
|
|
707
|
+
get(key: string): string | null;
|
|
708
|
+
setCachedToken(token: string): void;
|
|
709
|
+
getCachedToken(): string | null;
|
|
710
|
+
clear(): void;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
declare interface MessengerSessionCache {
|
|
714
|
+
getSettings(userId: string): MessengerSettingsResponse | null;
|
|
715
|
+
setSettings(userId: string, value: MessengerSettingsResponse): void;
|
|
716
|
+
getAnonUser(): AnonUserSessionData | null;
|
|
717
|
+
setAnonUser(value: AnonUserSessionData): void;
|
|
718
|
+
clear(userId: string): void;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
declare interface MessengerSessionContextValue extends AIAgentMessengerSessionContextValue {
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
declare interface MessengerSettingsResponse {
|
|
725
|
+
active_channel: {
|
|
726
|
+
channel_url: string;
|
|
727
|
+
attachment_mode: 'always' | 'handed_off_only' | 'off';
|
|
728
|
+
};
|
|
729
|
+
bot: {
|
|
730
|
+
bot_userid: string;
|
|
731
|
+
reply_to_file: boolean;
|
|
732
|
+
bot_profile_url: string;
|
|
733
|
+
bot_nickname: string;
|
|
734
|
+
special_notice: string;
|
|
735
|
+
is_special_notice_enabled: boolean;
|
|
736
|
+
show_handoff_button: boolean;
|
|
737
|
+
is_multiple_active_conversations_enabled: boolean;
|
|
738
|
+
};
|
|
739
|
+
appearance: {
|
|
740
|
+
selected_theme: 'light' | 'dark';
|
|
741
|
+
themes: {
|
|
742
|
+
light: {
|
|
743
|
+
primary_color: string;
|
|
744
|
+
bot_message_bg_color: string;
|
|
745
|
+
primary_contrast_color: string;
|
|
746
|
+
bot_message_bg_contrast_color: string;
|
|
747
|
+
};
|
|
748
|
+
dark: {
|
|
749
|
+
primary_color: string;
|
|
750
|
+
bot_message_bg_color: string;
|
|
751
|
+
primary_contrast_color: string;
|
|
752
|
+
bot_message_bg_contrast_color: string;
|
|
753
|
+
};
|
|
754
|
+
};
|
|
755
|
+
};
|
|
756
|
+
launcher: {
|
|
757
|
+
image_type: LauncherImageType;
|
|
758
|
+
image_url: string;
|
|
759
|
+
auto_open: boolean;
|
|
760
|
+
};
|
|
761
|
+
auto_created_user?: {
|
|
762
|
+
user_id: string;
|
|
763
|
+
session_token: string;
|
|
764
|
+
expire_at: number;
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
declare type MMKVModule = MMKV;
|
|
769
|
+
|
|
770
|
+
declare interface ModalContextProps {
|
|
771
|
+
children: ReactNode;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
export declare interface ModalContextValue {
|
|
775
|
+
openModal: <T = any>(render: (close: (value?: T) => void) => ReactNode) => Promise<T | null>;
|
|
776
|
+
currentModal: ModalItem | null;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
declare interface ModalItem<T = any> {
|
|
780
|
+
id: string;
|
|
781
|
+
render: (close: (value?: T) => void) => ReactNode;
|
|
782
|
+
resolve: (value: T) => void;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
export declare function ModalProvider({ children }: ModalContextProps): JSX.Element;
|
|
786
|
+
|
|
787
|
+
/** Configuration for NativeAdapter */
|
|
788
|
+
declare interface NativeAdapterConfig {
|
|
789
|
+
mmkv: MMKVModule;
|
|
790
|
+
imagePicker: ExpoImagePickerModule | CommunityImagePickerModule;
|
|
791
|
+
documentPicker: ExpoDocumentPickerModule | CommunityDocumentPickerModule;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/** Methods available from useNativeAdapterContext() */
|
|
795
|
+
declare interface NativeAdapterContextValue {
|
|
796
|
+
/**
|
|
797
|
+
* Launch camera to capture a photo
|
|
798
|
+
* @returns Array with single MediaFile, or null if cancelled
|
|
799
|
+
*/
|
|
800
|
+
captureCamera: (options?: MediaPickerOptions) => Promise<MediaFile[] | null>;
|
|
801
|
+
/**
|
|
802
|
+
* Select photos from gallery
|
|
803
|
+
* @returns Array of MediaFiles, or null if cancelled
|
|
804
|
+
*/
|
|
805
|
+
selectFromGallery: (options?: MediaPickerOptions) => Promise<MediaFile[] | null>;
|
|
806
|
+
/**
|
|
807
|
+
* Select files from file picker
|
|
808
|
+
* @returns Array of MediaFiles, or null if cancelled
|
|
809
|
+
*/
|
|
810
|
+
selectFile: (options?: MediaPickerOptions) => Promise<MediaFile[] | null>;
|
|
811
|
+
/**
|
|
812
|
+
* Key-value storage interface
|
|
813
|
+
*/
|
|
814
|
+
keyValueStorage: KeyValueStorage;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Provider for native adapter context.
|
|
819
|
+
* Requires native modules configuration.
|
|
820
|
+
*/
|
|
821
|
+
export declare const NativeAdapterProvider: ({ config, children }: NativeAdapterProviderProps) => JSX.Element;
|
|
822
|
+
|
|
823
|
+
declare interface NativeAdapterProviderProps {
|
|
824
|
+
config: NativeAdapterConfig;
|
|
825
|
+
children: ReactNode | ((context: NativeAdapterContextValue) => ReactNode);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
declare interface PaletteColor {
|
|
829
|
+
extraDark: string;
|
|
830
|
+
dark: string;
|
|
831
|
+
main: string;
|
|
832
|
+
light: string;
|
|
833
|
+
extraLight: string;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
declare interface PaletteShape {
|
|
837
|
+
primary: PaletteColor;
|
|
838
|
+
secondary: PaletteColor;
|
|
839
|
+
error: PaletteColor;
|
|
840
|
+
information: PaletteColor;
|
|
841
|
+
background700: string;
|
|
842
|
+
background600: string;
|
|
843
|
+
background500: string;
|
|
844
|
+
background400: string;
|
|
845
|
+
background300: string;
|
|
846
|
+
background200: string;
|
|
847
|
+
background100: string;
|
|
848
|
+
background50: string;
|
|
849
|
+
onlight: PaletteTextEmphasis;
|
|
850
|
+
ondark: PaletteTextEmphasis;
|
|
851
|
+
overlay: {
|
|
852
|
+
dark: string;
|
|
853
|
+
light: string;
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
declare interface PaletteTextEmphasis {
|
|
858
|
+
textHighEmphasis: string;
|
|
859
|
+
textMidEmphasis: string;
|
|
860
|
+
textLowEmphasis: string;
|
|
861
|
+
textDisabled: string;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Type utility for making all properties optional recursively
|
|
866
|
+
* Functions and Sets are preserved as-is without being made partial
|
|
867
|
+
*/
|
|
868
|
+
declare type PartialDeep<T> = T extends object ? T extends Set<unknown> ? T : T extends Function ? T : {
|
|
869
|
+
[P in keyof T]?: PartialDeep<T[P]>;
|
|
870
|
+
} : T;
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Strings type for React Native components
|
|
874
|
+
* Uses nested structure with lowercase keys
|
|
875
|
+
*/
|
|
876
|
+
declare type StringSet = {
|
|
877
|
+
conversation: AIAgentStringSet['conversation'] & {
|
|
878
|
+
attachment_camera: string;
|
|
879
|
+
attachment_photo: string;
|
|
880
|
+
attachment_document: string;
|
|
881
|
+
};
|
|
882
|
+
conversation_list: AIAgentStringSet['conversation_list'] & {
|
|
883
|
+
footer_title: string;
|
|
884
|
+
};
|
|
885
|
+
date_format: AIAgentStringSet['date_format'] & {};
|
|
886
|
+
csat: AIAgentStringSet['csat'] & {};
|
|
887
|
+
form: AIAgentStringSet['form'] & {};
|
|
888
|
+
common: AIAgentStringSet['common'] & {};
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
declare interface TypographyShape {
|
|
892
|
+
h1: TypographyVariant;
|
|
893
|
+
h2: TypographyVariant;
|
|
894
|
+
subtitle1: TypographyVariant;
|
|
895
|
+
subtitle2: TypographyVariant;
|
|
896
|
+
body1: TypographyVariant;
|
|
897
|
+
body2: TypographyVariant;
|
|
898
|
+
body3: TypographyVariant;
|
|
899
|
+
button: TypographyVariant;
|
|
900
|
+
caption1: TypographyVariant;
|
|
901
|
+
caption2: TypographyVariant;
|
|
902
|
+
caption3: TypographyVariant;
|
|
903
|
+
caption4: TypographyVariant;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
declare interface TypographyVariant {
|
|
907
|
+
fontSize: number | string;
|
|
908
|
+
fontWeight: number | string;
|
|
909
|
+
fontFamily?: string;
|
|
910
|
+
lineHeight?: number | string;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
export declare const useConversationContext: {
|
|
914
|
+
(): ConversationContextValue;
|
|
915
|
+
displayName: string;
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
export declare const useConversationListContext: {
|
|
919
|
+
(): ConversationListContextValue;
|
|
920
|
+
displayName: string;
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
export declare const useMessengerSessionContext: {
|
|
924
|
+
(): MessengerSessionContextValue;
|
|
925
|
+
displayName: string;
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
export declare const useModalContext: {
|
|
929
|
+
(): ModalContextValue;
|
|
930
|
+
displayName: string;
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
export declare const useNativeAdapterContext: {
|
|
934
|
+
(): NativeAdapterContextValue;
|
|
935
|
+
displayName: string;
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
declare type UserSession = {
|
|
939
|
+
userId: string;
|
|
940
|
+
authToken: string;
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* @deprecated Please use `ManualSessionInfo` or `AnonymousSessionInfo` instead.
|
|
945
|
+
* */
|
|
946
|
+
declare interface UserSessionInfo {
|
|
947
|
+
userId: string;
|
|
948
|
+
authToken: string;
|
|
949
|
+
sessionHandler: SessionHandler;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
export { }
|