@pedi/chika-sdk 1.0.4 → 1.0.6
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/README.md +80 -1
- package/dist/index.d.mts +99 -11
- package/dist/index.d.ts +99 -11
- package/dist/index.js +744 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +740 -70
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -3
package/README.md
CHANGED
|
@@ -14,16 +14,27 @@ Provides a drop-in React hook (`useChat`) that connects your React Native app to
|
|
|
14
14
|
- **Message deduplication** — Prevents duplicate messages from SSE echo and reconnection replays
|
|
15
15
|
- **Optimistic UI** — Messages appear in the local list instantly on send, before server confirmation
|
|
16
16
|
- **Type-safe chat domains** — Full generic support via `ChatDomain` so message types, roles, and attributes are enforced at compile time
|
|
17
|
+
- **Automatic retry on failure** — Failed message sends are automatically retried with exponential backoff before giving up
|
|
18
|
+
- **Offline message queuing** — Messages sent while offline are queued and flushed when connectivity returns
|
|
19
|
+
- **Network-aware reconnection** — SSE reconnection waits for network availability and uses exponential backoff instead of fixed delays
|
|
17
20
|
|
|
18
21
|
## Key Features
|
|
19
22
|
|
|
20
23
|
- `useChat<D>()` React hook with full TypeScript generics
|
|
21
24
|
- `createChatSession<D>()` imperative API for non-React usage
|
|
25
|
+
- **`useUnread()` hook** — Real-time unread count tracking via dedicated SSE stream with passive listening support
|
|
22
26
|
- Automatic SSE reconnection with configurable delay
|
|
23
27
|
- Platform-aware AppState handling (iOS vs Android)
|
|
24
28
|
- Optimistic message sending with deduplication
|
|
25
29
|
- Hash-based bucket routing for multi-server deployments
|
|
26
|
-
- Custom error classes (`ChatDisconnectedError`, `ChannelClosedError`)
|
|
30
|
+
- Custom error classes (`ChatDisconnectedError`, `ChannelClosedError`, `HttpError`, `RetryExhaustedError`, `QueueFullError`)
|
|
31
|
+
- Network resilience with automatic retry (exponential backoff, jitter, 429 Retry-After support)
|
|
32
|
+
- Offline message queue with per-message status tracking (`sending`, `queued`, `failed`)
|
|
33
|
+
- Optional `@react-native-community/netinfo` integration for network-aware reconnection
|
|
34
|
+
- Persistent queue storage via auto-detected MMKV or AsyncStorage
|
|
35
|
+
- Server-side idempotency keys to prevent duplicate messages on retry
|
|
36
|
+
- Per-message `cancelMessage()` and `retryMessage()` controls
|
|
37
|
+
- All resilience features togglable — set `resilience: false` to disable
|
|
27
38
|
|
|
28
39
|
## Quick Start
|
|
29
40
|
|
|
@@ -45,12 +56,80 @@ function ChatScreen({ bookingId, user }) {
|
|
|
45
56
|
}
|
|
46
57
|
```
|
|
47
58
|
|
|
59
|
+
### Unread Notifications
|
|
60
|
+
|
|
61
|
+
Monitor unread message counts in real-time — even for channels the user hasn't joined yet:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { useUnread } from '@pedi/chika-sdk';
|
|
65
|
+
|
|
66
|
+
function ChatListItem({ channelId, userId, config }) {
|
|
67
|
+
const { unreadCount, hasUnread, lastMessageAt } = useUnread({
|
|
68
|
+
config,
|
|
69
|
+
channelId,
|
|
70
|
+
participantId: userId,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<View>
|
|
75
|
+
<Text>{channelId}</Text>
|
|
76
|
+
{hasUnread && <Badge count={unreadCount} />}
|
|
77
|
+
</View>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The hook handles SSE reconnection and AppState-aware lifecycle management automatically. Disable it with `enabled: false` when `useChat` is already active on the same channel.
|
|
83
|
+
|
|
84
|
+
### Network Resilience
|
|
85
|
+
|
|
86
|
+
Resilience features automatically handle failures, offline scenarios, and network transitions:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { useChat, createManifest, createQueueStorage } from '@pedi/chika-sdk';
|
|
90
|
+
|
|
91
|
+
function ChatScreen({ bookingId, user }) {
|
|
92
|
+
const {
|
|
93
|
+
messages, status, sendMessage,
|
|
94
|
+
pendingMessages, cancelMessage, retryMessage,
|
|
95
|
+
} = useChat<PediChat>({
|
|
96
|
+
config: {
|
|
97
|
+
manifest: createManifest('https://chat.example.com'),
|
|
98
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
99
|
+
resilience: {
|
|
100
|
+
retry: { maxAttempts: 5 },
|
|
101
|
+
queueStorage: createQueueStorage() ?? undefined,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
channelId: `booking_${bookingId}`,
|
|
105
|
+
profile: { id: user.id, role: 'rider', name: user.name },
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Messages queue automatically when offline, retry on failure
|
|
109
|
+
await sendMessage('chat', 'Hello!');
|
|
110
|
+
|
|
111
|
+
// Show per-message status in UI
|
|
112
|
+
for (const msg of pendingMessages) {
|
|
113
|
+
if (msg.status === 'failed') {
|
|
114
|
+
// Show retry/cancel buttons
|
|
115
|
+
retryMessage(msg.optimisticId);
|
|
116
|
+
// or: cancelMessage(msg.optimisticId);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Resilience is enabled by default. Disable with `resilience: false` for manual control.
|
|
123
|
+
|
|
48
124
|
**Peer dependencies:** `react >= 18`, `react-native >= 0.72`
|
|
49
125
|
|
|
126
|
+
**Optional peer dependencies:** `@react-native-community/netinfo` (network monitoring), `react-native-mmkv` or `@react-native-async-storage/async-storage` (queue persistence)
|
|
127
|
+
|
|
50
128
|
## Documentation
|
|
51
129
|
|
|
52
130
|
See the [docs](./docs/) for detailed documentation:
|
|
53
131
|
|
|
54
132
|
- [API Reference](./docs/api-reference.md) — `useChat`, `createChatSession`, utilities, error classes, and all config options
|
|
55
133
|
- [Guides](./docs/guides.md) — Connection lifecycle, AppState handling, reconnection, deduplication, custom domains
|
|
134
|
+
- [Network Resilience Guide](./docs/resilience-guide.md) — Retry, offline queue, network monitoring, persistent storage, and configuration
|
|
56
135
|
- [AI Agent Integration Guide](./docs/llm-integration-guide.md) — Patterns, recipes, pitfalls, and checklists for LLM-assisted implementation
|
package/dist/index.d.mts
CHANGED
|
@@ -1,23 +1,84 @@
|
|
|
1
1
|
import { ChatManifest, ChatDomain, DefaultDomain, Participant, Message, MessageAttributes, SendMessageResponse } from '@pedi/chika-types';
|
|
2
2
|
export { ChatBucket, ChatDomain, ChatManifest, DefaultDomain, MarkReadRequest, Message, MessageAttributes, Participant, PediChat, PediLocation, PediMessageAttributes, PediMessageType, PediParticipantMeta, PediRole, PediVehicle, SSEUnreadClearEvent, SSEUnreadEvent, SSEUnreadUpdateEvent, SendMessageResponse, UnreadCountResponse } from '@pedi/chika-types';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
interface RetryConfig {
|
|
5
|
+
maxAttempts: number;
|
|
6
|
+
baseDelayMs: number;
|
|
7
|
+
maxDelayMs: number;
|
|
8
|
+
jitterFactor: number;
|
|
9
|
+
}
|
|
10
|
+
declare function calculateBackoff(attempt: number, config: RetryConfig): number;
|
|
11
|
+
declare function isRetryableError(error: unknown): boolean;
|
|
12
|
+
declare function resolveRetryConfig(resilience: {
|
|
13
|
+
retry?: Partial<RetryConfig> | false;
|
|
14
|
+
} | false | undefined): RetryConfig | null;
|
|
15
|
+
declare function withRetry<T>(fn: () => Promise<T>, config?: RetryConfig, signal?: AbortSignal): Promise<T>;
|
|
16
|
+
|
|
17
|
+
interface NetworkMonitor {
|
|
18
|
+
isConnected(): boolean;
|
|
19
|
+
subscribe(cb: (connected: boolean) => void): () => void;
|
|
20
|
+
waitForOnline(signal?: AbortSignal): Promise<void>;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
}
|
|
23
|
+
declare function createNetworkMonitor(): NetworkMonitor;
|
|
24
|
+
|
|
25
|
+
interface QueueStorage {
|
|
26
|
+
getItem(key: string): Promise<string | null>;
|
|
27
|
+
setItem(key: string, value: string): Promise<void>;
|
|
28
|
+
removeItem(key: string): Promise<void>;
|
|
29
|
+
}
|
|
5
30
|
/**
|
|
6
|
-
*
|
|
31
|
+
* Auto-detect the best available storage for queue persistence.
|
|
32
|
+
* Priority: react-native-mmkv (fastest, sync) > AsyncStorage > null.
|
|
33
|
+
* Returns `null` if neither is installed — no hard dependencies.
|
|
7
34
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
35
|
+
* Usage:
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { createQueueStorage } from '@pedi/chika-sdk';
|
|
38
|
+
*
|
|
39
|
+
* const config: ChatConfig = {
|
|
40
|
+
* resilience: {
|
|
41
|
+
* queueStorage: createQueueStorage() ?? undefined,
|
|
42
|
+
* },
|
|
43
|
+
* };
|
|
44
|
+
* ```
|
|
12
45
|
*/
|
|
46
|
+
declare function createQueueStorage(): QueueStorage | null;
|
|
47
|
+
/**
|
|
48
|
+
* Creates a QueueStorage adapter backed by `@react-native-async-storage/async-storage`.
|
|
49
|
+
* Returns `null` if the package is not installed.
|
|
50
|
+
*/
|
|
51
|
+
declare function createAsyncStorageAdapter(): QueueStorage | null;
|
|
52
|
+
type MessageSendStatus = 'sending' | 'queued' | 'failed';
|
|
53
|
+
interface QueuedMessage {
|
|
54
|
+
optimisticId: string;
|
|
55
|
+
status: MessageSendStatus;
|
|
56
|
+
error?: Error;
|
|
57
|
+
retryCount: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type ChatStatus = 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'closed' | 'error';
|
|
61
|
+
interface ResilienceConfig {
|
|
62
|
+
/** Retry config overrides. Set false to disable retry entirely. */
|
|
63
|
+
retry?: Partial<RetryConfig> | false;
|
|
64
|
+
/** Enable offline message queuing. Default: true. */
|
|
65
|
+
offlineQueue?: boolean;
|
|
66
|
+
/** Max queued messages. Default: 50. */
|
|
67
|
+
maxQueueSize?: number;
|
|
68
|
+
/** Inject custom NetworkMonitor (bypasses built-in NetInfo detection). */
|
|
69
|
+
networkMonitor?: NetworkMonitor;
|
|
70
|
+
/** Persistent storage adapter for queue (AsyncStorage/MMKV/etc). */
|
|
71
|
+
queueStorage?: QueueStorage;
|
|
72
|
+
}
|
|
13
73
|
/**
|
|
14
74
|
* Configuration for the chat SDK.
|
|
15
75
|
*
|
|
16
76
|
* @property manifest - Bucket routing manifest for server URL resolution.
|
|
17
77
|
* @property headers - Custom headers applied to all HTTP and SSE requests (e.g., auth tokens).
|
|
18
|
-
* @property reconnectDelayMs -
|
|
78
|
+
* @property reconnectDelayMs - Base delay before SSE reconnection attempt. Default: 3000ms.
|
|
19
79
|
* @property backgroundGraceMs - Grace period before teardown on app background. Default: 2000ms on Android, 0ms on iOS.
|
|
20
80
|
* @property optimisticSend - Append messages to the local array immediately on send. Default: true.
|
|
81
|
+
* @property resilience - Network resilience options. Enabled by default. Set false to disable all.
|
|
21
82
|
*/
|
|
22
83
|
interface ChatConfig {
|
|
23
84
|
manifest: ChatManifest;
|
|
@@ -25,6 +86,7 @@ interface ChatConfig {
|
|
|
25
86
|
reconnectDelayMs?: number;
|
|
26
87
|
backgroundGraceMs?: number;
|
|
27
88
|
optimisticSend?: boolean;
|
|
89
|
+
resilience?: ResilienceConfig | false;
|
|
28
90
|
}
|
|
29
91
|
interface UseChatOptions<D extends ChatDomain = DefaultDomain> {
|
|
30
92
|
config: ChatConfig;
|
|
@@ -39,11 +101,18 @@ interface UseChatReturn<D extends ChatDomain = DefaultDomain> {
|
|
|
39
101
|
error: Error | null;
|
|
40
102
|
sendMessage: (type: D['messageType'], body: string, attributes?: MessageAttributes<D>) => Promise<SendMessageResponse>;
|
|
41
103
|
disconnect: () => void;
|
|
104
|
+
/** Per-message send status for queued/retrying messages. Empty when resilience disabled. */
|
|
105
|
+
pendingMessages: QueuedMessage[];
|
|
106
|
+
/** Cancel a queued or failed message by its optimistic ID. */
|
|
107
|
+
cancelMessage: (optimisticId: string) => void;
|
|
108
|
+
/** Retry a failed message by its optimistic ID. */
|
|
109
|
+
retryMessage: (optimisticId: string) => void;
|
|
42
110
|
}
|
|
43
111
|
|
|
44
112
|
/**
|
|
45
113
|
* React hook for real-time chat over SSE.
|
|
46
|
-
* Manages connection lifecycle, AppState transitions, message deduplication,
|
|
114
|
+
* Manages connection lifecycle, AppState transitions, message deduplication, reconnection,
|
|
115
|
+
* and optional network resilience (retry, offline queue, network monitoring).
|
|
47
116
|
*
|
|
48
117
|
* @template D - Chat domain type for role/message type narrowing. Defaults to DefaultDomain.
|
|
49
118
|
*/
|
|
@@ -74,11 +143,12 @@ interface ChatSession<D extends ChatDomain = DefaultDomain> {
|
|
|
74
143
|
channelId: string;
|
|
75
144
|
initialParticipants: Participant<D>[];
|
|
76
145
|
initialMessages: Message<D>[];
|
|
77
|
-
|
|
146
|
+
networkMonitor: NetworkMonitor | null;
|
|
147
|
+
sendMessage: (type: D['messageType'], body: string, attributes?: MessageAttributes<D>, idempotencyKey?: string) => Promise<SendMessageResponse>;
|
|
78
148
|
markAsRead: (messageId: string) => Promise<void>;
|
|
79
149
|
disconnect: () => void;
|
|
80
150
|
}
|
|
81
|
-
declare function createChatSession<D extends ChatDomain = DefaultDomain>(config: ChatConfig, channelId: string, profile: Participant<D>, callbacks: SessionCallbacks<D
|
|
151
|
+
declare function createChatSession<D extends ChatDomain = DefaultDomain>(config: ChatConfig, channelId: string, profile: Participant<D>, callbacks: SessionCallbacks<D>, networkMonitor?: NetworkMonitor): Promise<ChatSession<D>>;
|
|
82
152
|
|
|
83
153
|
/**
|
|
84
154
|
* Creates a single-server manifest. Use this when all channels route to the same server.
|
|
@@ -97,6 +167,7 @@ interface SSEConnectionConfig {
|
|
|
97
167
|
reconnectDelayMs?: number;
|
|
98
168
|
lastEventId?: string;
|
|
99
169
|
customEvents?: string[];
|
|
170
|
+
networkMonitor?: NetworkMonitor;
|
|
100
171
|
}
|
|
101
172
|
interface SSEConnectionCallbacks {
|
|
102
173
|
onOpen?: () => void;
|
|
@@ -107,6 +178,7 @@ interface SSEConnectionCallbacks {
|
|
|
107
178
|
}
|
|
108
179
|
interface SSEConnection {
|
|
109
180
|
close: () => void;
|
|
181
|
+
reconnectImmediate: () => void;
|
|
110
182
|
}
|
|
111
183
|
declare function createSSEConnection(config: SSEConnectionConfig, callbacks: SSEConnectionCallbacks): SSEConnection;
|
|
112
184
|
|
|
@@ -118,5 +190,21 @@ declare class ChannelClosedError extends Error {
|
|
|
118
190
|
readonly channelId: string;
|
|
119
191
|
constructor(channelId: string);
|
|
120
192
|
}
|
|
193
|
+
declare class HttpError extends Error {
|
|
194
|
+
readonly status: number;
|
|
195
|
+
readonly body: string;
|
|
196
|
+
readonly retryAfter?: number | undefined;
|
|
197
|
+
constructor(status: number, body: string, retryAfter?: number | undefined);
|
|
198
|
+
}
|
|
199
|
+
declare class RetryExhaustedError extends Error {
|
|
200
|
+
readonly operation: string;
|
|
201
|
+
readonly attempts: number;
|
|
202
|
+
readonly lastError: Error;
|
|
203
|
+
constructor(operation: string, attempts: number, lastError: Error);
|
|
204
|
+
}
|
|
205
|
+
declare class QueueFullError extends Error {
|
|
206
|
+
readonly maxSize: number;
|
|
207
|
+
constructor(maxSize: number);
|
|
208
|
+
}
|
|
121
209
|
|
|
122
|
-
export { ChannelClosedError, type ChatConfig, ChatDisconnectedError, type ChatSession, type ChatStatus, type SSEConnection, type SSEConnectionCallbacks, type SSEConnectionConfig, type SessionCallbacks, type UseChatOptions, type UseChatReturn, type UseUnreadOptions, type UseUnreadReturn, createChatSession, createManifest, createSSEConnection, resolveServerUrl, useChat, useUnread };
|
|
210
|
+
export { ChannelClosedError, type ChatConfig, ChatDisconnectedError, type ChatSession, type ChatStatus, HttpError, type MessageSendStatus, type NetworkMonitor, QueueFullError, type QueueStorage, type QueuedMessage, type ResilienceConfig, type RetryConfig, RetryExhaustedError, type SSEConnection, type SSEConnectionCallbacks, type SSEConnectionConfig, type SessionCallbacks, type UseChatOptions, type UseChatReturn, type UseUnreadOptions, type UseUnreadReturn, calculateBackoff, createAsyncStorageAdapter, createChatSession, createManifest, createNetworkMonitor, createQueueStorage, createSSEConnection, isRetryableError, resolveRetryConfig, resolveServerUrl, useChat, useUnread, withRetry };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,84 @@
|
|
|
1
1
|
import { ChatManifest, ChatDomain, DefaultDomain, Participant, Message, MessageAttributes, SendMessageResponse } from '@pedi/chika-types';
|
|
2
2
|
export { ChatBucket, ChatDomain, ChatManifest, DefaultDomain, MarkReadRequest, Message, MessageAttributes, Participant, PediChat, PediLocation, PediMessageAttributes, PediMessageType, PediParticipantMeta, PediRole, PediVehicle, SSEUnreadClearEvent, SSEUnreadEvent, SSEUnreadUpdateEvent, SendMessageResponse, UnreadCountResponse } from '@pedi/chika-types';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
interface RetryConfig {
|
|
5
|
+
maxAttempts: number;
|
|
6
|
+
baseDelayMs: number;
|
|
7
|
+
maxDelayMs: number;
|
|
8
|
+
jitterFactor: number;
|
|
9
|
+
}
|
|
10
|
+
declare function calculateBackoff(attempt: number, config: RetryConfig): number;
|
|
11
|
+
declare function isRetryableError(error: unknown): boolean;
|
|
12
|
+
declare function resolveRetryConfig(resilience: {
|
|
13
|
+
retry?: Partial<RetryConfig> | false;
|
|
14
|
+
} | false | undefined): RetryConfig | null;
|
|
15
|
+
declare function withRetry<T>(fn: () => Promise<T>, config?: RetryConfig, signal?: AbortSignal): Promise<T>;
|
|
16
|
+
|
|
17
|
+
interface NetworkMonitor {
|
|
18
|
+
isConnected(): boolean;
|
|
19
|
+
subscribe(cb: (connected: boolean) => void): () => void;
|
|
20
|
+
waitForOnline(signal?: AbortSignal): Promise<void>;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
}
|
|
23
|
+
declare function createNetworkMonitor(): NetworkMonitor;
|
|
24
|
+
|
|
25
|
+
interface QueueStorage {
|
|
26
|
+
getItem(key: string): Promise<string | null>;
|
|
27
|
+
setItem(key: string, value: string): Promise<void>;
|
|
28
|
+
removeItem(key: string): Promise<void>;
|
|
29
|
+
}
|
|
5
30
|
/**
|
|
6
|
-
*
|
|
31
|
+
* Auto-detect the best available storage for queue persistence.
|
|
32
|
+
* Priority: react-native-mmkv (fastest, sync) > AsyncStorage > null.
|
|
33
|
+
* Returns `null` if neither is installed — no hard dependencies.
|
|
7
34
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
35
|
+
* Usage:
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { createQueueStorage } from '@pedi/chika-sdk';
|
|
38
|
+
*
|
|
39
|
+
* const config: ChatConfig = {
|
|
40
|
+
* resilience: {
|
|
41
|
+
* queueStorage: createQueueStorage() ?? undefined,
|
|
42
|
+
* },
|
|
43
|
+
* };
|
|
44
|
+
* ```
|
|
12
45
|
*/
|
|
46
|
+
declare function createQueueStorage(): QueueStorage | null;
|
|
47
|
+
/**
|
|
48
|
+
* Creates a QueueStorage adapter backed by `@react-native-async-storage/async-storage`.
|
|
49
|
+
* Returns `null` if the package is not installed.
|
|
50
|
+
*/
|
|
51
|
+
declare function createAsyncStorageAdapter(): QueueStorage | null;
|
|
52
|
+
type MessageSendStatus = 'sending' | 'queued' | 'failed';
|
|
53
|
+
interface QueuedMessage {
|
|
54
|
+
optimisticId: string;
|
|
55
|
+
status: MessageSendStatus;
|
|
56
|
+
error?: Error;
|
|
57
|
+
retryCount: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type ChatStatus = 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'closed' | 'error';
|
|
61
|
+
interface ResilienceConfig {
|
|
62
|
+
/** Retry config overrides. Set false to disable retry entirely. */
|
|
63
|
+
retry?: Partial<RetryConfig> | false;
|
|
64
|
+
/** Enable offline message queuing. Default: true. */
|
|
65
|
+
offlineQueue?: boolean;
|
|
66
|
+
/** Max queued messages. Default: 50. */
|
|
67
|
+
maxQueueSize?: number;
|
|
68
|
+
/** Inject custom NetworkMonitor (bypasses built-in NetInfo detection). */
|
|
69
|
+
networkMonitor?: NetworkMonitor;
|
|
70
|
+
/** Persistent storage adapter for queue (AsyncStorage/MMKV/etc). */
|
|
71
|
+
queueStorage?: QueueStorage;
|
|
72
|
+
}
|
|
13
73
|
/**
|
|
14
74
|
* Configuration for the chat SDK.
|
|
15
75
|
*
|
|
16
76
|
* @property manifest - Bucket routing manifest for server URL resolution.
|
|
17
77
|
* @property headers - Custom headers applied to all HTTP and SSE requests (e.g., auth tokens).
|
|
18
|
-
* @property reconnectDelayMs -
|
|
78
|
+
* @property reconnectDelayMs - Base delay before SSE reconnection attempt. Default: 3000ms.
|
|
19
79
|
* @property backgroundGraceMs - Grace period before teardown on app background. Default: 2000ms on Android, 0ms on iOS.
|
|
20
80
|
* @property optimisticSend - Append messages to the local array immediately on send. Default: true.
|
|
81
|
+
* @property resilience - Network resilience options. Enabled by default. Set false to disable all.
|
|
21
82
|
*/
|
|
22
83
|
interface ChatConfig {
|
|
23
84
|
manifest: ChatManifest;
|
|
@@ -25,6 +86,7 @@ interface ChatConfig {
|
|
|
25
86
|
reconnectDelayMs?: number;
|
|
26
87
|
backgroundGraceMs?: number;
|
|
27
88
|
optimisticSend?: boolean;
|
|
89
|
+
resilience?: ResilienceConfig | false;
|
|
28
90
|
}
|
|
29
91
|
interface UseChatOptions<D extends ChatDomain = DefaultDomain> {
|
|
30
92
|
config: ChatConfig;
|
|
@@ -39,11 +101,18 @@ interface UseChatReturn<D extends ChatDomain = DefaultDomain> {
|
|
|
39
101
|
error: Error | null;
|
|
40
102
|
sendMessage: (type: D['messageType'], body: string, attributes?: MessageAttributes<D>) => Promise<SendMessageResponse>;
|
|
41
103
|
disconnect: () => void;
|
|
104
|
+
/** Per-message send status for queued/retrying messages. Empty when resilience disabled. */
|
|
105
|
+
pendingMessages: QueuedMessage[];
|
|
106
|
+
/** Cancel a queued or failed message by its optimistic ID. */
|
|
107
|
+
cancelMessage: (optimisticId: string) => void;
|
|
108
|
+
/** Retry a failed message by its optimistic ID. */
|
|
109
|
+
retryMessage: (optimisticId: string) => void;
|
|
42
110
|
}
|
|
43
111
|
|
|
44
112
|
/**
|
|
45
113
|
* React hook for real-time chat over SSE.
|
|
46
|
-
* Manages connection lifecycle, AppState transitions, message deduplication,
|
|
114
|
+
* Manages connection lifecycle, AppState transitions, message deduplication, reconnection,
|
|
115
|
+
* and optional network resilience (retry, offline queue, network monitoring).
|
|
47
116
|
*
|
|
48
117
|
* @template D - Chat domain type for role/message type narrowing. Defaults to DefaultDomain.
|
|
49
118
|
*/
|
|
@@ -74,11 +143,12 @@ interface ChatSession<D extends ChatDomain = DefaultDomain> {
|
|
|
74
143
|
channelId: string;
|
|
75
144
|
initialParticipants: Participant<D>[];
|
|
76
145
|
initialMessages: Message<D>[];
|
|
77
|
-
|
|
146
|
+
networkMonitor: NetworkMonitor | null;
|
|
147
|
+
sendMessage: (type: D['messageType'], body: string, attributes?: MessageAttributes<D>, idempotencyKey?: string) => Promise<SendMessageResponse>;
|
|
78
148
|
markAsRead: (messageId: string) => Promise<void>;
|
|
79
149
|
disconnect: () => void;
|
|
80
150
|
}
|
|
81
|
-
declare function createChatSession<D extends ChatDomain = DefaultDomain>(config: ChatConfig, channelId: string, profile: Participant<D>, callbacks: SessionCallbacks<D
|
|
151
|
+
declare function createChatSession<D extends ChatDomain = DefaultDomain>(config: ChatConfig, channelId: string, profile: Participant<D>, callbacks: SessionCallbacks<D>, networkMonitor?: NetworkMonitor): Promise<ChatSession<D>>;
|
|
82
152
|
|
|
83
153
|
/**
|
|
84
154
|
* Creates a single-server manifest. Use this when all channels route to the same server.
|
|
@@ -97,6 +167,7 @@ interface SSEConnectionConfig {
|
|
|
97
167
|
reconnectDelayMs?: number;
|
|
98
168
|
lastEventId?: string;
|
|
99
169
|
customEvents?: string[];
|
|
170
|
+
networkMonitor?: NetworkMonitor;
|
|
100
171
|
}
|
|
101
172
|
interface SSEConnectionCallbacks {
|
|
102
173
|
onOpen?: () => void;
|
|
@@ -107,6 +178,7 @@ interface SSEConnectionCallbacks {
|
|
|
107
178
|
}
|
|
108
179
|
interface SSEConnection {
|
|
109
180
|
close: () => void;
|
|
181
|
+
reconnectImmediate: () => void;
|
|
110
182
|
}
|
|
111
183
|
declare function createSSEConnection(config: SSEConnectionConfig, callbacks: SSEConnectionCallbacks): SSEConnection;
|
|
112
184
|
|
|
@@ -118,5 +190,21 @@ declare class ChannelClosedError extends Error {
|
|
|
118
190
|
readonly channelId: string;
|
|
119
191
|
constructor(channelId: string);
|
|
120
192
|
}
|
|
193
|
+
declare class HttpError extends Error {
|
|
194
|
+
readonly status: number;
|
|
195
|
+
readonly body: string;
|
|
196
|
+
readonly retryAfter?: number | undefined;
|
|
197
|
+
constructor(status: number, body: string, retryAfter?: number | undefined);
|
|
198
|
+
}
|
|
199
|
+
declare class RetryExhaustedError extends Error {
|
|
200
|
+
readonly operation: string;
|
|
201
|
+
readonly attempts: number;
|
|
202
|
+
readonly lastError: Error;
|
|
203
|
+
constructor(operation: string, attempts: number, lastError: Error);
|
|
204
|
+
}
|
|
205
|
+
declare class QueueFullError extends Error {
|
|
206
|
+
readonly maxSize: number;
|
|
207
|
+
constructor(maxSize: number);
|
|
208
|
+
}
|
|
121
209
|
|
|
122
|
-
export { ChannelClosedError, type ChatConfig, ChatDisconnectedError, type ChatSession, type ChatStatus, type SSEConnection, type SSEConnectionCallbacks, type SSEConnectionConfig, type SessionCallbacks, type UseChatOptions, type UseChatReturn, type UseUnreadOptions, type UseUnreadReturn, createChatSession, createManifest, createSSEConnection, resolveServerUrl, useChat, useUnread };
|
|
210
|
+
export { ChannelClosedError, type ChatConfig, ChatDisconnectedError, type ChatSession, type ChatStatus, HttpError, type MessageSendStatus, type NetworkMonitor, QueueFullError, type QueueStorage, type QueuedMessage, type ResilienceConfig, type RetryConfig, RetryExhaustedError, type SSEConnection, type SSEConnectionCallbacks, type SSEConnectionConfig, type SessionCallbacks, type UseChatOptions, type UseChatReturn, type UseUnreadOptions, type UseUnreadReturn, calculateBackoff, createAsyncStorageAdapter, createChatSession, createManifest, createNetworkMonitor, createQueueStorage, createSSEConnection, isRetryableError, resolveRetryConfig, resolveServerUrl, useChat, useUnread, withRetry };
|