@blario/react-native 0.1.6 → 0.1.7

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/src/blar.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { BackendTransport } from './backend/backend-transport.ts';
2
2
  import type { BlarIdentity } from './backend/identity.ts';
3
3
  import type { MessageMetadata } from './backend/message-metadata.ts';
4
+ import { attempt } from './telemetry/contain.ts';
4
5
 
5
6
  export interface MessageMetadataOptions {
6
7
  includeTextDom: boolean;
@@ -49,19 +50,19 @@ class BlarClient {
49
50
  }
50
51
 
51
52
  open(): void {
52
- this.chat?.open();
53
+ attempt('Blar.open', () => this.chat?.open());
53
54
  }
54
55
 
55
56
  close(): void {
56
- this.chat?.close();
57
+ attempt('Blar.close', () => this.chat?.close());
57
58
  }
58
59
 
59
60
  getUnreadCount(): number {
60
- return this.chat?.getUnread() ?? 0;
61
+ return attempt('Blar.getUnreadCount', () => this.chat?.getUnread()) ?? 0;
61
62
  }
62
63
 
63
64
  isChatOpen(): boolean {
64
- return this.chat?.isOpen() ?? false;
65
+ return attempt('Blar.isChatOpen', () => this.chat?.isOpen()) ?? false;
65
66
  }
66
67
 
67
68
  async setUser(identity: BlarIdentity): Promise<void> {
@@ -81,15 +82,15 @@ class BlarClient {
81
82
  }
82
83
 
83
84
  isConnected(): boolean {
84
- return this.transport?.isConnected() ?? false;
85
+ return attempt('Blar.isConnected', () => this.transport?.isConnected()) ?? false;
85
86
  }
86
87
 
87
88
  getTabId(): string | null {
88
- return this.transport?.getTabId() ?? null;
89
+ return attempt('Blar.getTabId', () => this.transport?.getTabId()) ?? null;
89
90
  }
90
91
 
91
92
  getSessionState(): ReturnType<BackendTransport['getState']> | null {
92
- return this.transport?.getState() ?? null;
93
+ return attempt('Blar.getSessionState', () => this.transport?.getState()) ?? null;
93
94
  }
94
95
 
95
96
  getMessageMetadata(options: MessageMetadataOptions = { includeTextDom: false }): Promise<MessageMetadata | null> {
@@ -1,9 +1,10 @@
1
1
  import React, { useEffect, useRef } from 'react';
2
- import { Animated, BackHandler, Dimensions, Easing, Keyboard, Platform, Pressable, StyleSheet, View } from 'react-native';
2
+ import { Animated, BackHandler, Dimensions, Easing, Keyboard, type KeyboardEvent, Platform, Pressable, StyleSheet, View } from 'react-native';
3
3
 
4
4
  import { useInsets } from '../ui/useInsets.ts';
5
5
  import type { UiStrings } from '../ui/strings.ts';
6
6
  import type { SheetMode } from './chat-state.ts';
7
+ import { attempt, contain } from '../telemetry/contain.ts';
7
8
 
8
9
  export interface ChatSheetProps {
9
10
  mode: SheetMode;
@@ -26,7 +27,7 @@ function useKeyboardInset(active: boolean, homeIndicator: number): Animated.Valu
26
27
  inset.setValue(0);
27
28
  return undefined;
28
29
  }
29
- const subscription = Keyboard.addListener('keyboardWillChangeFrame', (event) => {
30
+ const subscription = Keyboard.addListener('keyboardWillChangeFrame', contain('ChatSheet.keyboard', (event: KeyboardEvent) => {
30
31
  const covered = Dimensions.get('window').height - event.endCoordinates.screenY;
31
32
  Animated.timing(inset, {
32
33
  // The keyboard covers the home-indicator inset, so the sheet's bottom padding sits under it, not above it.
@@ -35,7 +36,7 @@ function useKeyboardInset(active: boolean, homeIndicator: number): Animated.Valu
35
36
  easing: Easing.out(Easing.cubic),
36
37
  useNativeDriver: false,
37
38
  }).start();
38
- });
39
+ }));
39
40
  return () => subscription.remove();
40
41
  }, [active, homeIndicator, inset]);
41
42
  return inset;
@@ -58,7 +59,7 @@ export function ChatSheet({ mode, mounted, strings, onClose, children }: ChatShe
58
59
  return undefined;
59
60
  }
60
61
  const subscription = BackHandler.addEventListener('hardwareBackPress', () => {
61
- onClose();
62
+ attempt('ChatSheet.back', onClose);
62
63
  return true;
63
64
  });
64
65
  return () => subscription.remove();
@@ -72,7 +73,7 @@ export function ChatSheet({ mode, mounted, strings, onClose, children }: ChatShe
72
73
  return (
73
74
  <View style={StyleSheet.absoluteFill} pointerEvents={isOpen ? 'auto' : 'none'}>
74
75
  <Animated.View style={[styles.backdrop, { opacity: backdropOpacity }]}>
75
- <Pressable accessibilityLabel={strings.chatClose} style={StyleSheet.absoluteFill} onPress={onClose} />
76
+ <Pressable accessibilityLabel={strings.chatClose} style={StyleSheet.absoluteFill} onPress={contain('ChatSheet.backdrop', onClose)} />
76
77
  </Animated.View>
77
78
  <Animated.View style={[styles.container, { paddingTop: insets.top + TOP_GAP, paddingBottom: keyboardInset }]} pointerEvents="box-none">
78
79
  <Animated.View
@@ -10,6 +10,7 @@ import type { SessionRequest } from './chat-coordinator.ts';
10
10
  import { type ChatNavigation, leavesChat } from './navigation.ts';
11
11
  import { buildWidgetShell, type WidgetShellOptions } from './widget-shell.ts';
12
12
  import { loadWebView, type WebViewHandle } from './webview.ts';
13
+ import { attempt, contain } from '../telemetry/contain.ts';
13
14
 
14
15
  export interface ChatViewProps {
15
16
  shell: WidgetShellOptions;
@@ -58,7 +59,7 @@ export function ChatView({ shell, unavailableText, getMetadata, getProof, onClos
58
59
  );
59
60
 
60
61
  const onMessage = useCallback(
61
- (event: WebViewMessageEvent) => {
62
+ contain('ChatView.message', (event: WebViewMessageEvent) => {
62
63
  const message = parsePageMessage(event.nativeEvent.data);
63
64
  if (message === null) {
64
65
  return;
@@ -74,18 +75,19 @@ export function ChatView({ shell, unavailableText, getMetadata, getProof, onClos
74
75
  } else {
75
76
  log?.('webview ready');
76
77
  }
77
- },
78
+ }),
78
79
  [handleCall, log, onClosed, onSessionChanged],
79
80
  );
80
81
 
81
82
  const onNavigation = useCallback(
82
- (navigation: ChatNavigation) => {
83
- if (!leavesChat(navigation, shell.apiBaseUrl)) {
84
- return true;
85
- }
86
- Linking.openURL(navigation.url).catch(() => log?.('chat link could not be opened'));
87
- return false;
88
- },
83
+ (navigation: ChatNavigation) =>
84
+ attempt('ChatView.navigation', () => {
85
+ if (!leavesChat(navigation, shell.apiBaseUrl)) {
86
+ return true;
87
+ }
88
+ Linking.openURL(navigation.url).catch(() => log?.('chat link could not be opened'));
89
+ return false;
90
+ }) ?? false,
89
91
  [log, shell.apiBaseUrl],
90
92
  );
91
93
 
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { Pressable, StyleSheet, Text, View } from 'react-native';
3
3
 
4
4
  import { useInsets } from '../ui/useInsets.ts';
5
+ import { contain } from '../telemetry/contain.ts';
5
6
 
6
7
  export interface LauncherPlacement {
7
8
  side: 'left' | 'right';
@@ -26,7 +27,7 @@ export function Launcher({ unread, label, color, placement, onPress }: LauncherP
26
27
  <Pressable
27
28
  accessibilityRole="button"
28
29
  accessibilityLabel={label}
29
- onPress={onPress}
30
+ onPress={contain('Launcher.press', onPress)}
30
31
  style={[styles.button, horizontal, { bottom: insets.bottom + placement.offsetY, backgroundColor: color }]}
31
32
  >
32
33
  <View style={styles.bubble}>