@chatlychat/react-native 0.0.0-stage → 0.1.1
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 +208 -2
- package/dist/ChatlyProvider.d.ts +69 -0
- package/dist/ChatlyProvider.d.ts.map +1 -0
- package/dist/ChatlyProvider.js +146 -0
- package/dist/ChatlyProvider.js.map +1 -0
- package/dist/ChatlyWidget.d.ts +15 -0
- package/dist/ChatlyWidget.d.ts.map +1 -0
- package/dist/ChatlyWidget.js +122 -0
- package/dist/ChatlyWidget.js.map +1 -0
- package/dist/blocks/money.d.ts +56 -0
- package/dist/blocks/money.d.ts.map +1 -0
- package/dist/blocks/money.js +82 -0
- package/dist/blocks/money.js.map +1 -0
- package/dist/blocks/money.parity.spec.d.ts +2 -0
- package/dist/blocks/money.parity.spec.d.ts.map +1 -0
- package/dist/blocks/money.parity.spec.js +87 -0
- package/dist/blocks/money.parity.spec.js.map +1 -0
- package/dist/blocks/read-envelope.d.ts +15 -0
- package/dist/blocks/read-envelope.d.ts.map +1 -0
- package/dist/blocks/read-envelope.js +196 -0
- package/dist/blocks/read-envelope.js.map +1 -0
- package/dist/blocks/read-envelope.parity.spec.d.ts +2 -0
- package/dist/blocks/read-envelope.parity.spec.d.ts.map +1 -0
- package/dist/blocks/read-envelope.parity.spec.js +146 -0
- package/dist/blocks/read-envelope.parity.spec.js.map +1 -0
- package/dist/blocks/types.d.ts +171 -0
- package/dist/blocks/types.d.ts.map +1 -0
- package/dist/blocks/types.js +3 -0
- package/dist/blocks/types.js.map +1 -0
- package/dist/client/RealtimeClient.d.ts +29 -0
- package/dist/client/RealtimeClient.d.ts.map +1 -0
- package/dist/client/RealtimeClient.js +113 -0
- package/dist/client/RealtimeClient.js.map +1 -0
- package/dist/client/RealtimeClient.spec.d.ts +2 -0
- package/dist/client/RealtimeClient.spec.d.ts.map +1 -0
- package/dist/client/RealtimeClient.spec.js +123 -0
- package/dist/client/RealtimeClient.spec.js.map +1 -0
- package/dist/client/RestClient.d.ts +160 -0
- package/dist/client/RestClient.d.ts.map +1 -0
- package/dist/client/RestClient.js +395 -0
- package/dist/client/RestClient.js.map +1 -0
- package/dist/client/RestClient.spec.d.ts +2 -0
- package/dist/client/RestClient.spec.d.ts.map +1 -0
- package/dist/client/RestClient.spec.js +267 -0
- package/dist/client/RestClient.spec.js.map +1 -0
- package/dist/client/types.d.ts +148 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +14 -0
- package/dist/client/types.js.map +1 -0
- package/dist/components/Composer.d.ts +35 -0
- package/dist/components/Composer.d.ts.map +1 -0
- package/dist/components/Composer.js +180 -0
- package/dist/components/Composer.js.map +1 -0
- package/dist/components/HelpCenter.d.ts +13 -0
- package/dist/components/HelpCenter.d.ts.map +1 -0
- package/dist/components/HelpCenter.js +96 -0
- package/dist/components/HelpCenter.js.map +1 -0
- package/dist/components/MessageBlocks.d.ts +41 -0
- package/dist/components/MessageBlocks.d.ts.map +1 -0
- package/dist/components/MessageBlocks.js +167 -0
- package/dist/components/MessageBlocks.js.map +1 -0
- package/dist/components/MessageBubble.d.ts +14 -0
- package/dist/components/MessageBubble.d.ts.map +1 -0
- package/dist/components/MessageBubble.js +87 -0
- package/dist/components/MessageBubble.js.map +1 -0
- package/dist/components/MessageBubble.spec.d.ts +2 -0
- package/dist/components/MessageBubble.spec.d.ts.map +1 -0
- package/dist/components/MessageBubble.spec.js +207 -0
- package/dist/components/MessageBubble.spec.js.map +1 -0
- package/dist/components/MessageCanvas.d.ts +39 -0
- package/dist/components/MessageCanvas.d.ts.map +1 -0
- package/dist/components/MessageCanvas.js +144 -0
- package/dist/components/MessageCanvas.js.map +1 -0
- package/dist/components/MessageCanvas.spec.d.ts +2 -0
- package/dist/components/MessageCanvas.spec.d.ts.map +1 -0
- package/dist/components/MessageCanvas.spec.js +142 -0
- package/dist/components/MessageCanvas.spec.js.map +1 -0
- package/dist/components/MessagesList.d.ts +8 -0
- package/dist/components/MessagesList.d.ts.map +1 -0
- package/dist/components/MessagesList.js +58 -0
- package/dist/components/MessagesList.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/push/registerPushToken.d.ts +12 -0
- package/dist/push/registerPushToken.d.ts.map +1 -0
- package/dist/push/registerPushToken.js +32 -0
- package/dist/push/registerPushToken.js.map +1 -0
- package/dist/storage/TokenStore.d.ts +53 -0
- package/dist/storage/TokenStore.d.ts.map +1 -0
- package/dist/storage/TokenStore.js +89 -0
- package/dist/storage/TokenStore.js.map +1 -0
- package/dist/test/react-native-dom.d.ts +97 -0
- package/dist/test/react-native-dom.d.ts.map +1 -0
- package/dist/test/react-native-dom.js +155 -0
- package/dist/test/react-native-dom.js.map +1 -0
- package/dist/test/react-native-dom.spec.d.ts +2 -0
- package/dist/test/react-native-dom.spec.d.ts.map +1 -0
- package/dist/test/react-native-dom.spec.js +83 -0
- package/dist/test/react-native-dom.spec.js.map +1 -0
- package/dist/theme/ChatlyTheme.d.ts +37 -0
- package/dist/theme/ChatlyTheme.d.ts.map +1 -0
- package/dist/theme/ChatlyTheme.js +2 -0
- package/dist/theme/ChatlyTheme.js.map +1 -0
- package/dist/theme/defaultTheme.d.ts +7 -0
- package/dist/theme/defaultTheme.d.ts.map +1 -0
- package/dist/theme/defaultTheme.js +37 -0
- package/dist/theme/defaultTheme.js.map +1 -0
- package/dist/useChatly.d.ts +3 -0
- package/dist/useChatly.d.ts.map +1 -0
- package/dist/useChatly.js +10 -0
- package/dist/useChatly.js.map +1 -0
- package/package.json +49 -3
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stale-session recovery for the React Native SDK.
|
|
3
|
+
*
|
|
4
|
+
* When visitor tokens became signed envelopes, the server began refusing
|
|
5
|
+
* pre-signature tokens with a 403 carrying `visitor_session_upgrade_required`
|
|
6
|
+
* (or `visitor_session_invalid`). The browser widget and `@chatlychat/sdk-js`
|
|
7
|
+
* both recover from that in place; the mobile SDKs did not, so a mid-session
|
|
8
|
+
* visitor on an IDV-enabled channel got one hard failure and then kept
|
|
9
|
+
* failing, because the dead token stayed in AsyncStorage across launches.
|
|
10
|
+
*
|
|
11
|
+
* These pin the recovery to the widget's exact semantics:
|
|
12
|
+
* - only a 403, and only for `visitor_session_*` codes;
|
|
13
|
+
* - exactly one retry;
|
|
14
|
+
* - the replay re-inits with the REMEMBERED identity, so the contact — and
|
|
15
|
+
* therefore the conversation history — comes back;
|
|
16
|
+
* - the dead token is replaced in PERSISTENT storage, not just in memory;
|
|
17
|
+
* - the Idempotency-Key is stable across the replay.
|
|
18
|
+
*/
|
|
19
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
20
|
+
vi.mock('react-native', () => ({ Platform: { OS: 'ios' } }));
|
|
21
|
+
/**
|
|
22
|
+
* The REAL `@react-native-async-storage/async-storage` is used here, not a
|
|
23
|
+
* stub of `TokenStore`: outside a device its entry point is the web build,
|
|
24
|
+
* which is a thin shim over `window.localStorage`. Backing that with a Map
|
|
25
|
+
* exercises the whole persistence path the SDK actually runs — which is the
|
|
26
|
+
* point, since the bug being fixed is a dead token surviving on DISK.
|
|
27
|
+
*
|
|
28
|
+
* `TokenStore` loads the module with `require()`, which vite-node resolves
|
|
29
|
+
* outside the mock registry, so `vi.mock` on it would not take effect anyway.
|
|
30
|
+
*/
|
|
31
|
+
const store = new Map();
|
|
32
|
+
vi.stubGlobal('window', {
|
|
33
|
+
localStorage: {
|
|
34
|
+
getItem: (k) => store.get(k) ?? null,
|
|
35
|
+
setItem: (k, v) => {
|
|
36
|
+
store.set(k, v);
|
|
37
|
+
},
|
|
38
|
+
removeItem: (k) => {
|
|
39
|
+
store.delete(k);
|
|
40
|
+
},
|
|
41
|
+
clear: () => {
|
|
42
|
+
store.clear();
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
import { RestClient } from './RestClient';
|
|
47
|
+
const PUBLIC_ID = 'pub_test';
|
|
48
|
+
const TOKEN_KEY = `chatly:vt:${PUBLIC_ID}`;
|
|
49
|
+
const IDENTITY_KEY = `chatly:id:${PUBLIC_ID}`;
|
|
50
|
+
const calls = [];
|
|
51
|
+
function record(url, init) {
|
|
52
|
+
const headers = (init.headers ?? {});
|
|
53
|
+
const call = {
|
|
54
|
+
path: new URL(url).pathname,
|
|
55
|
+
body: JSON.parse(String(init.body)),
|
|
56
|
+
idempotencyKey: headers['idempotency-key'] ?? null,
|
|
57
|
+
};
|
|
58
|
+
calls.push(call);
|
|
59
|
+
return call;
|
|
60
|
+
}
|
|
61
|
+
function json(status, payload) {
|
|
62
|
+
return new Response(JSON.stringify(payload), {
|
|
63
|
+
status,
|
|
64
|
+
headers: { 'content-type': 'application/json' },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function initPayload(token) {
|
|
68
|
+
return {
|
|
69
|
+
session: {
|
|
70
|
+
token,
|
|
71
|
+
contactId: 'c-1',
|
|
72
|
+
workspaceId: 'w-1',
|
|
73
|
+
brandId: 'b-1',
|
|
74
|
+
channelId: 'ch-1',
|
|
75
|
+
},
|
|
76
|
+
workspace: { id: 'w-1', name: 'Acme' },
|
|
77
|
+
branding: {},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const IDENTITY = { externalId: 'u-42', userHash: 'deadbeef' };
|
|
81
|
+
function newClient() {
|
|
82
|
+
return new RestClient({ publicId: PUBLIC_ID, apiHost: 'api.test' });
|
|
83
|
+
}
|
|
84
|
+
/** Puts a (now stale) token and a remembered identity on "disk", exactly as a
|
|
85
|
+
* previous app launch would have left them. */
|
|
86
|
+
function seedDisk() {
|
|
87
|
+
store.set(TOKEN_KEY, 'stale-token');
|
|
88
|
+
store.set(IDENTITY_KEY, JSON.stringify(IDENTITY));
|
|
89
|
+
}
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
calls.length = 0;
|
|
92
|
+
store.clear();
|
|
93
|
+
});
|
|
94
|
+
describe('RestClient stale-session recovery', () => {
|
|
95
|
+
it('replays the call once after re-initing with the remembered identity', async () => {
|
|
96
|
+
seedDisk();
|
|
97
|
+
let repliesSeen = 0;
|
|
98
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
99
|
+
const call = record(url, init);
|
|
100
|
+
if (call.path === '/v1/widget/init') {
|
|
101
|
+
return Promise.resolve(json(200, initPayload('fresh-token')));
|
|
102
|
+
}
|
|
103
|
+
repliesSeen += 1;
|
|
104
|
+
if (repliesSeen === 1) {
|
|
105
|
+
return Promise.resolve(json(403, { code: 'visitor_session_upgrade_required' }));
|
|
106
|
+
}
|
|
107
|
+
return Promise.resolve(json(200, { message: { id: 'm-1' } }));
|
|
108
|
+
}));
|
|
109
|
+
const client = newClient();
|
|
110
|
+
await expect(client.reply('conv-1', 'hello')).resolves.toEqual({ message: { id: 'm-1' } });
|
|
111
|
+
// Exactly two calls to the original endpoint, one init wedged between.
|
|
112
|
+
expect(calls.map((c) => c.path)).toEqual([
|
|
113
|
+
'/v1/widget/messages',
|
|
114
|
+
'/v1/widget/init',
|
|
115
|
+
'/v1/widget/messages',
|
|
116
|
+
]);
|
|
117
|
+
// The re-init carried the remembered identity, so the replay lands on the
|
|
118
|
+
// same contact and the visitor's history survives.
|
|
119
|
+
expect(calls[1]?.body['identity']).toEqual(IDENTITY);
|
|
120
|
+
// ...and did NOT re-send the token the server just refused.
|
|
121
|
+
expect(calls[1]?.body['visitorToken']).toBeUndefined();
|
|
122
|
+
// The replay used the fresh token.
|
|
123
|
+
expect(calls[0]?.body['visitorToken']).toBe('stale-token');
|
|
124
|
+
expect(calls[2]?.body['visitorToken']).toBe('fresh-token');
|
|
125
|
+
// A replayed write must coalesce server-side, not double-send.
|
|
126
|
+
expect(calls[2]?.idempotencyKey).toBe(calls[0]?.idempotencyKey);
|
|
127
|
+
expect(calls[2]?.idempotencyKey).not.toBe(calls[1]?.idempotencyKey);
|
|
128
|
+
// Persisted, not just cached: the next launch must not repeat the failure.
|
|
129
|
+
expect(store.get(TOKEN_KEY)).toBe('fresh-token');
|
|
130
|
+
});
|
|
131
|
+
it('recovers `visitor_session_invalid` too, not just the upgrade code', async () => {
|
|
132
|
+
seedDisk();
|
|
133
|
+
let repliesSeen = 0;
|
|
134
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
135
|
+
const call = record(url, init);
|
|
136
|
+
if (call.path === '/v1/widget/init') {
|
|
137
|
+
return Promise.resolve(json(200, initPayload('fresh-token')));
|
|
138
|
+
}
|
|
139
|
+
repliesSeen += 1;
|
|
140
|
+
return repliesSeen === 1
|
|
141
|
+
? Promise.resolve(json(403, { code: 'visitor_session_invalid' }))
|
|
142
|
+
: Promise.resolve(json(200, { ok: true }));
|
|
143
|
+
}));
|
|
144
|
+
const client = newClient();
|
|
145
|
+
await expect(client.reply('conv-1', 'hello')).resolves.toEqual({ ok: true });
|
|
146
|
+
expect(calls.filter((c) => c.path === '/v1/widget/messages')).toHaveLength(2);
|
|
147
|
+
});
|
|
148
|
+
it('re-boots init in place when init itself is refused', async () => {
|
|
149
|
+
seedDisk();
|
|
150
|
+
let initsSeen = 0;
|
|
151
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
152
|
+
record(url, init);
|
|
153
|
+
initsSeen += 1;
|
|
154
|
+
return initsSeen === 1
|
|
155
|
+
? Promise.resolve(json(403, { code: 'visitor_session_invalid' }))
|
|
156
|
+
: Promise.resolve(json(200, initPayload('fresh-token')));
|
|
157
|
+
}));
|
|
158
|
+
const client = newClient();
|
|
159
|
+
await client.init();
|
|
160
|
+
expect(calls.map((c) => c.path)).toEqual(['/v1/widget/init', '/v1/widget/init']);
|
|
161
|
+
expect(calls[0]?.body['visitorToken']).toBe('stale-token');
|
|
162
|
+
expect(calls[1]?.body['visitorToken']).toBeUndefined();
|
|
163
|
+
expect(calls[1]?.body['identity']).toEqual(IDENTITY);
|
|
164
|
+
expect(store.get(TOKEN_KEY)).toBe('fresh-token');
|
|
165
|
+
});
|
|
166
|
+
it('does NOT retry a 403 with an unrelated code', async () => {
|
|
167
|
+
seedDisk();
|
|
168
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
169
|
+
record(url, init);
|
|
170
|
+
return Promise.resolve(json(403, { code: 'widget_origin_not_allowed' }));
|
|
171
|
+
}));
|
|
172
|
+
const client = newClient();
|
|
173
|
+
await expect(client.reply('conv-1', 'hello')).rejects.toThrow(/403/);
|
|
174
|
+
// One attempt, no init: retrying an origin refusal just fails again.
|
|
175
|
+
expect(calls.map((c) => c.path)).toEqual(['/v1/widget/messages']);
|
|
176
|
+
// The token was NOT thrown away — it was never the problem.
|
|
177
|
+
expect(store.get(TOKEN_KEY)).toBe('stale-token');
|
|
178
|
+
});
|
|
179
|
+
it('gives up after exactly one retry when the replay is refused too', async () => {
|
|
180
|
+
seedDisk();
|
|
181
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
182
|
+
const call = record(url, init);
|
|
183
|
+
return call.path === '/v1/widget/init'
|
|
184
|
+
? Promise.resolve(json(200, initPayload('fresh-token')))
|
|
185
|
+
: Promise.resolve(json(403, { code: 'visitor_session_invalid' }));
|
|
186
|
+
}));
|
|
187
|
+
const client = newClient();
|
|
188
|
+
await expect(client.reply('conv-1', 'hello')).rejects.toThrow(/403/);
|
|
189
|
+
expect(calls.filter((c) => c.path === '/v1/widget/messages')).toHaveLength(2);
|
|
190
|
+
});
|
|
191
|
+
it('does not retry a non-403 failure', async () => {
|
|
192
|
+
seedDisk();
|
|
193
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
194
|
+
record(url, init);
|
|
195
|
+
return Promise.resolve(json(500, { code: 'visitor_session_invalid' }));
|
|
196
|
+
}));
|
|
197
|
+
const client = newClient();
|
|
198
|
+
await expect(client.reply('conv-1', 'hello')).rejects.toThrow(/500/);
|
|
199
|
+
expect(calls).toHaveLength(1);
|
|
200
|
+
});
|
|
201
|
+
it('persists the identity only after the server accepts it', async () => {
|
|
202
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
203
|
+
record(url, init);
|
|
204
|
+
return Promise.resolve(json(200, initPayload('fresh-token')));
|
|
205
|
+
}));
|
|
206
|
+
const client = newClient();
|
|
207
|
+
expect(store.get(IDENTITY_KEY)).toBeUndefined();
|
|
208
|
+
await client.init(IDENTITY);
|
|
209
|
+
expect(JSON.parse(store.get(IDENTITY_KEY) ?? 'null')).toEqual(IDENTITY);
|
|
210
|
+
});
|
|
211
|
+
it('forgets the remembered identity on clearToken, so logout cannot be undone by a recovery', async () => {
|
|
212
|
+
seedDisk();
|
|
213
|
+
const client = newClient();
|
|
214
|
+
await client.clearToken();
|
|
215
|
+
expect(store.get(TOKEN_KEY)).toBeUndefined();
|
|
216
|
+
expect(store.get(IDENTITY_KEY)).toBeUndefined();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
/**
|
|
220
|
+
* The envelope the API really sends.
|
|
221
|
+
*
|
|
222
|
+
* Every fixture above uses `{ code }` at the top level, and the API has never
|
|
223
|
+
* sent that: `app-exception.filter.ts` ends with `send({ error: body })`. So
|
|
224
|
+
* `isStaleSession` read `undefined`, returned false every time, and the
|
|
225
|
+
* recovery this whole file is about never fired in production — the suite was
|
|
226
|
+
* green because the fixtures agreed with the bug rather than with the server.
|
|
227
|
+
*
|
|
228
|
+
* Third place with the identical defect: the browser widget, `sdk-js`, and
|
|
229
|
+
* here. Each was written by reading the previous one, which is how a bug
|
|
230
|
+
* travels between SDKs that look independent.
|
|
231
|
+
*/
|
|
232
|
+
describe('the real error envelope', () => {
|
|
233
|
+
it('recovers a stale session from a NESTED 403', async () => {
|
|
234
|
+
seedDisk();
|
|
235
|
+
let repliesSeen = 0;
|
|
236
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
237
|
+
const call = record(url, init);
|
|
238
|
+
if (call.path === '/v1/widget/init') {
|
|
239
|
+
return Promise.resolve(json(200, initPayload('fresh-token')));
|
|
240
|
+
}
|
|
241
|
+
repliesSeen += 1;
|
|
242
|
+
if (repliesSeen === 1) {
|
|
243
|
+
return Promise.resolve(json(403, { error: { code: 'visitor_session_upgrade_required', message: 'stale' } }));
|
|
244
|
+
}
|
|
245
|
+
return Promise.resolve(json(200, { ok: true }));
|
|
246
|
+
}));
|
|
247
|
+
await newClient().listConversations();
|
|
248
|
+
// Refused once, re-initialised with the remembered identity, replayed.
|
|
249
|
+
expect(calls.filter((c) => c.path === '/v1/widget/conversations/list')).toHaveLength(2);
|
|
250
|
+
expect(calls.some((c) => c.path === '/v1/widget/init')).toBe(true);
|
|
251
|
+
});
|
|
252
|
+
it('still does NOT retry a nested non-session 403', async () => {
|
|
253
|
+
// An origin refusal fails identically on a retry; retrying is just
|
|
254
|
+
// slower. Reading the nested code must not make every 403 recoverable.
|
|
255
|
+
seedDisk();
|
|
256
|
+
vi.stubGlobal('fetch', vi.fn((url, init) => {
|
|
257
|
+
const call = record(url, init);
|
|
258
|
+
if (call.path === '/v1/widget/init') {
|
|
259
|
+
return Promise.resolve(json(200, initPayload('fresh-token')));
|
|
260
|
+
}
|
|
261
|
+
return Promise.resolve(json(403, { error: { code: 'forbidden', message: 'nope' } }));
|
|
262
|
+
}));
|
|
263
|
+
await expect(newClient().listConversations()).rejects.toThrow();
|
|
264
|
+
expect(calls.filter((c) => c.path === '/v1/widget/conversations/list')).toHaveLength(1);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
//# sourceMappingURL=RestClient.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RestClient.spec.js","sourceRoot":"","sources":["../../src/client/RestClient.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire types shared between the REST + realtime clients and the React layer.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the server-side widget contract in `apps/widget/src/client.ts`
|
|
5
|
+
* and the realtime envelope in `packages/shared/src/realtime/index.ts`. We do
|
|
6
|
+
* not import from those packages directly to keep the published SDK free of
|
|
7
|
+
* workspace-internal dependencies.
|
|
8
|
+
*/
|
|
9
|
+
export interface ChatlyConfig {
|
|
10
|
+
/** Public workspace identifier, e.g. `pub_abc123`. */
|
|
11
|
+
publicId: string;
|
|
12
|
+
/** API host (no scheme). Defaults to `api.chatly.com`. */
|
|
13
|
+
apiHost?: string;
|
|
14
|
+
/** Override the realtime host. Defaults to the apiHost. */
|
|
15
|
+
realtimeHost?: string;
|
|
16
|
+
/** When false, the SDK uses `http://`/`ws://` instead of TLS. Defaults to true. */
|
|
17
|
+
secure?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface ChatlyIdentity {
|
|
20
|
+
externalId: string;
|
|
21
|
+
email?: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
/** HMAC-SHA256 of the externalId using the workspace identity secret. */
|
|
24
|
+
userHash?: string;
|
|
25
|
+
attributes?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
export interface SessionState {
|
|
28
|
+
token: string;
|
|
29
|
+
contactId: string;
|
|
30
|
+
workspaceId: string;
|
|
31
|
+
brandId: string;
|
|
32
|
+
channelId: string;
|
|
33
|
+
}
|
|
34
|
+
export interface InitResponse {
|
|
35
|
+
session: SessionState;
|
|
36
|
+
workspace: {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
};
|
|
40
|
+
branding: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
export interface StartResponse {
|
|
43
|
+
conversation: {
|
|
44
|
+
id: string;
|
|
45
|
+
};
|
|
46
|
+
message: {
|
|
47
|
+
id: string;
|
|
48
|
+
body: string;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export type ConversationStatus = 'open' | 'snoozed' | 'closed' | 'pending';
|
|
53
|
+
export interface ConversationSummary {
|
|
54
|
+
id: string;
|
|
55
|
+
status: ConversationStatus;
|
|
56
|
+
subject: string | null;
|
|
57
|
+
lastMessagePreview: string | null;
|
|
58
|
+
lastMessageAt: string | null;
|
|
59
|
+
unreadContactCount: number;
|
|
60
|
+
createdAt: string;
|
|
61
|
+
}
|
|
62
|
+
export type MessageAuthor = 'contact' | 'agent' | 'bot' | 'system';
|
|
63
|
+
export type MessageKind = 'text' | 'image' | 'file' | 'attachment_only' | 'event' | 'internal_note';
|
|
64
|
+
/**
|
|
65
|
+
* One file or image attached to a message. Produced by `POST /v1/widget/uploads`
|
|
66
|
+
* and echoed back on every message payload that carries the attachment.
|
|
67
|
+
*
|
|
68
|
+
* Wire format is identical across all 4 mobile SDKs — the SDK renders
|
|
69
|
+
* `image/*` mime types as inline thumbnails and anything else as a file row.
|
|
70
|
+
*/
|
|
71
|
+
export interface Attachment {
|
|
72
|
+
id: string;
|
|
73
|
+
url: string;
|
|
74
|
+
filename: string;
|
|
75
|
+
mimeType: string;
|
|
76
|
+
sizeBytes: number;
|
|
77
|
+
}
|
|
78
|
+
export interface MessageRow {
|
|
79
|
+
id: string;
|
|
80
|
+
authorType: MessageAuthor;
|
|
81
|
+
kind: MessageKind;
|
|
82
|
+
body: string;
|
|
83
|
+
attachments?: Attachment[];
|
|
84
|
+
createdAt: string;
|
|
85
|
+
/**
|
|
86
|
+
* Rich blocks — cards, a carousel, quick replies, a status line.
|
|
87
|
+
*
|
|
88
|
+
* `unknown` on purpose, and validated by `readBlocksEnvelope` at render
|
|
89
|
+
* time rather than typed here. The row comes off the wire: a server newer
|
|
90
|
+
* than this app sends block types it does not know, and a row written
|
|
91
|
+
* before a field was validated must produce the most of the message that
|
|
92
|
+
* CAN be drawn rather than a type error. A declared shape here would be a
|
|
93
|
+
* claim about a payload this package does not control.
|
|
94
|
+
*
|
|
95
|
+
* Absent until `blocks` was added to the message surface, so `undefined`
|
|
96
|
+
* and `null` both mean "plain text".
|
|
97
|
+
*/
|
|
98
|
+
blocks?: unknown;
|
|
99
|
+
/** A Tier 2 canvas — a form inside the bubble. `unknown` for the same reason. */
|
|
100
|
+
canvas?: unknown;
|
|
101
|
+
}
|
|
102
|
+
export interface KbResult {
|
|
103
|
+
id: string;
|
|
104
|
+
slug: string;
|
|
105
|
+
title: string;
|
|
106
|
+
excerpt: string;
|
|
107
|
+
}
|
|
108
|
+
export interface KbArticle {
|
|
109
|
+
id: string;
|
|
110
|
+
slug: string;
|
|
111
|
+
title: string;
|
|
112
|
+
body: string;
|
|
113
|
+
bodyHtml: string | null;
|
|
114
|
+
updatedAt: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Realtime envelope. Keep in lockstep with
|
|
118
|
+
* `packages/shared/src/realtime/index.ts` (protocol version 1).
|
|
119
|
+
*/
|
|
120
|
+
export declare const REALTIME_PROTOCOL_VERSION = 1;
|
|
121
|
+
export type RealtimeEventType = 'session.connected' | 'session.disconnected' | 'session.ping' | 'session.pong' | 'session.error' | 'subscribe' | 'unsubscribe' | 'replay.completed' | 'presence.online' | 'presence.offline' | 'presence.away' | 'conversation.created' | 'conversation.updated' | 'conversation.assigned' | 'conversation.closed' | 'conversation.reopened' | 'message.created' | 'message.updated' | 'message.deleted' | 'message.read' | 'message.delivered' | 'typing.start' | 'typing.stop' | 'visitor.identified' | 'visitor.page_view' | 'trigger.fired' | 'ai.copilot.suggestion' | 'ai.agent.message';
|
|
122
|
+
export interface RealtimeEnvelope<P = unknown> {
|
|
123
|
+
v: typeof REALTIME_PROTOCOL_VERSION;
|
|
124
|
+
type: RealtimeEventType;
|
|
125
|
+
id: string;
|
|
126
|
+
ts: number;
|
|
127
|
+
workspace_id: string;
|
|
128
|
+
payload: P;
|
|
129
|
+
}
|
|
130
|
+
export interface MessageCreatedPayload {
|
|
131
|
+
id: string;
|
|
132
|
+
conversationId: string;
|
|
133
|
+
authorType: MessageAuthor;
|
|
134
|
+
authorId: string | null;
|
|
135
|
+
body: string;
|
|
136
|
+
attachments: unknown[];
|
|
137
|
+
createdAt: string;
|
|
138
|
+
}
|
|
139
|
+
export type PushPlatform = 'ios' | 'android' | 'expo';
|
|
140
|
+
export interface PushTokenRegistration {
|
|
141
|
+
platform: PushPlatform;
|
|
142
|
+
token: string;
|
|
143
|
+
/** Bundle identifier or app id; helpful for multi-app workspaces. */
|
|
144
|
+
bundleId?: string;
|
|
145
|
+
/** Client app version (e.g. '1.4.2'); included in the registration record. */
|
|
146
|
+
appVersion?: string;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;AACnE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,iBAAiB,GAAG,OAAO,GAAG,eAAe,CAAC;AAEpG;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,aAAa,CAAC;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,MAAM,MAAM,iBAAiB,GACzB,mBAAmB,GACnB,sBAAsB,GACtB,cAAc,GACd,cAAc,GACd,eAAe,GACf,WAAW,GACX,aAAa,GACb,kBAAkB,GAClB,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,sBAAsB,GACtB,sBAAsB,GACtB,uBAAuB,GACvB,qBAAqB,GACrB,uBAAuB,GACvB,iBAAiB,GACjB,iBAAiB,GACjB,iBAAiB,GACjB,cAAc,GACd,mBAAmB,GACnB,cAAc,GACd,aAAa,GACb,oBAAoB,GACpB,mBAAmB,GACnB,eAAe,GACf,uBAAuB,GACvB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,OAAO;IAC3C,CAAC,EAAE,OAAO,yBAAyB,CAAC;IACpC,IAAI,EAAE,iBAAiB,CAAC;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire types shared between the REST + realtime clients and the React layer.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the server-side widget contract in `apps/widget/src/client.ts`
|
|
5
|
+
* and the realtime envelope in `packages/shared/src/realtime/index.ts`. We do
|
|
6
|
+
* not import from those packages directly to keep the published SDK free of
|
|
7
|
+
* workspace-internal dependencies.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Realtime envelope. Keep in lockstep with
|
|
11
|
+
* `packages/shared/src/realtime/index.ts` (protocol version 1).
|
|
12
|
+
*/
|
|
13
|
+
export const REALTIME_PROTOCOL_VERSION = 1;
|
|
14
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgHH;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ComposerProps {
|
|
3
|
+
conversationId: string | null;
|
|
4
|
+
/**
|
|
5
|
+
* Called after a message is successfully sent. When `conversationId` is
|
|
6
|
+
* null, the composer starts a new conversation and the returned id is
|
|
7
|
+
* delivered here.
|
|
8
|
+
*/
|
|
9
|
+
onSent?: (conversationId: string) => void;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Bottom composer with a paperclip attachment button, multi-line text input,
|
|
14
|
+
* and a send button.
|
|
15
|
+
*
|
|
16
|
+
* Attachment picking depends on a document-picker module being available at
|
|
17
|
+
* runtime. We do NOT take a hard dependency on any picker package — instead
|
|
18
|
+
* the picker is resolved lazily via `globalThis.__chatlyPicker`. Hosts that
|
|
19
|
+
* want native attachment picking install one of:
|
|
20
|
+
* - `expo-document-picker`
|
|
21
|
+
* - `@react-native-documents/picker`
|
|
22
|
+
* - `react-native-document-picker`
|
|
23
|
+
* and assign a small shim that returns `{ bytes, filename, mimeType }`. When
|
|
24
|
+
* no picker is present the button degrades gracefully (still visible, but
|
|
25
|
+
* surfaces a "Pick disabled" hint).
|
|
26
|
+
*/
|
|
27
|
+
declare global {
|
|
28
|
+
var __chatlyPicker: (() => Promise<{
|
|
29
|
+
bytes: Uint8Array;
|
|
30
|
+
filename: string;
|
|
31
|
+
mimeType: string;
|
|
32
|
+
} | null>) | undefined;
|
|
33
|
+
}
|
|
34
|
+
export declare function Composer({ conversationId, onSent, placeholder, }: ComposerProps): React.JSX.Element;
|
|
35
|
+
//# sourceMappingURL=Composer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Composer.d.ts","sourceRoot":"","sources":["../../src/components/Composer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAexC,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;GAcG;AACH,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,cAAc,EACd,CAAC,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC,GACjF,SAAS,CAAC;CACf;AAED,wBAAgB,QAAQ,CAAC,EACvB,cAAc,EACd,MAAM,EACN,WAA+B,GAChC,EAAE,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAgOnC"}
|