@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,142 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The Tier 2 canvas on a native screen.
|
|
4
|
+
*
|
|
5
|
+
* ── The two properties that are easy to get wrong ──────────────────────
|
|
6
|
+
*
|
|
7
|
+
* The canvas on screen must be REPLACED by whatever the submission returns.
|
|
8
|
+
* A refused submission comes back as the same canvas with messages on it and
|
|
9
|
+
* a changed total comes back as a FRESH step rather than a charge — so a
|
|
10
|
+
* renderer that kept rendering its prop would show the shopper the old price
|
|
11
|
+
* beside the new errors, and would show a stale "Confirm · $48.20" after the
|
|
12
|
+
* server had already quoted $51.
|
|
13
|
+
*
|
|
14
|
+
* And a `hostEvent` on the answer must reach the APP. That is how 3-D Secure
|
|
15
|
+
* works on a phone: the step says "now run this", the app runs it natively.
|
|
16
|
+
* A renderer that swallowed it would leave a payment half-done with nothing
|
|
17
|
+
* on screen to say so.
|
|
18
|
+
*/
|
|
19
|
+
import { cleanup, render, screen, waitFor } from '@testing-library/react';
|
|
20
|
+
import userEvent from '@testing-library/user-event';
|
|
21
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
22
|
+
import { ChatlyContext } from '../ChatlyProvider';
|
|
23
|
+
import { MessageCanvas } from './MessageCanvas';
|
|
24
|
+
import { defaultTheme } from '../theme/defaultTheme';
|
|
25
|
+
afterEach(cleanup);
|
|
26
|
+
const CONV = 'conv-1';
|
|
27
|
+
const CANVAS = {
|
|
28
|
+
v: 1,
|
|
29
|
+
canvasId: 'buy-nd10',
|
|
30
|
+
title: 'Confirm purchase · $48.20',
|
|
31
|
+
fields: [
|
|
32
|
+
{ type: 'text', name: 'note', label: 'Gift note', placeholder: 'Optional' },
|
|
33
|
+
{ type: 'checkbox', name: 'gift', label: 'Send as a gift' },
|
|
34
|
+
],
|
|
35
|
+
actions: [
|
|
36
|
+
{ id: 'confirm', kind: 'submit', label: 'Buy now', style: 'primary' },
|
|
37
|
+
{ id: 'cancel', kind: 'cancel', label: 'Not now' },
|
|
38
|
+
],
|
|
39
|
+
state: 'quote:4820',
|
|
40
|
+
};
|
|
41
|
+
function harness(opts) {
|
|
42
|
+
const submitCanvas = vi.fn(() => opts.reject === true
|
|
43
|
+
? Promise.reject(new Error('offline'))
|
|
44
|
+
: Promise.resolve(opts.answer ?? { canvas: CANVAS, errors: {} }));
|
|
45
|
+
const value = {
|
|
46
|
+
theme: defaultTheme,
|
|
47
|
+
rest: { submitCanvas },
|
|
48
|
+
...(opts.onAction === undefined ? {} : { onAction: opts.onAction }),
|
|
49
|
+
};
|
|
50
|
+
render(_jsx(ChatlyContext.Provider, { value: value, children: _jsx(MessageCanvas, { canvas: CANVAS, conversationId: CONV, messageId: "m1" }) }));
|
|
51
|
+
return { submitCanvas };
|
|
52
|
+
}
|
|
53
|
+
describe('MessageCanvas', () => {
|
|
54
|
+
it('renders the title, the fields and the actions', () => {
|
|
55
|
+
harness({});
|
|
56
|
+
expect(screen.getByText('Confirm purchase · $48.20')).toBeDefined();
|
|
57
|
+
expect(screen.getByLabelText('Gift note')).toBeDefined();
|
|
58
|
+
expect(screen.getByRole('button', { name: 'Buy now' })).toBeDefined();
|
|
59
|
+
});
|
|
60
|
+
it('submits the typed values, with a checkbox as a boolean', async () => {
|
|
61
|
+
const h = harness({});
|
|
62
|
+
await userEvent.type(screen.getByLabelText('Gift note'), 'happy birthday');
|
|
63
|
+
await userEvent.click(screen.getByRole('button', { name: 'Send as a gift' }));
|
|
64
|
+
await userEvent.click(screen.getByRole('button', { name: 'Buy now' }));
|
|
65
|
+
await waitFor(() => {
|
|
66
|
+
expect(h.submitCanvas).toHaveBeenCalledWith(CONV, {
|
|
67
|
+
messageId: 'm1',
|
|
68
|
+
actionId: 'confirm',
|
|
69
|
+
values: { note: 'happy birthday', gift: true },
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
it('REPLACES the step with what the server returned', async () => {
|
|
74
|
+
// A changed total comes back as a fresh step rather than a charge. The
|
|
75
|
+
// old title must be gone, or the shopper confirms a price that moved.
|
|
76
|
+
const next = {
|
|
77
|
+
canvas: { ...CANVAS, title: 'Price changed · $51.00' },
|
|
78
|
+
errors: {},
|
|
79
|
+
};
|
|
80
|
+
harness({ answer: next });
|
|
81
|
+
await userEvent.click(screen.getByRole('button', { name: 'Buy now' }));
|
|
82
|
+
await waitFor(() => {
|
|
83
|
+
expect(screen.getByText('Price changed · $51.00')).toBeDefined();
|
|
84
|
+
});
|
|
85
|
+
expect(screen.queryByText('Confirm purchase · $48.20')).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
it('shows a per-field error from a refused submission', async () => {
|
|
88
|
+
harness({ answer: { canvas: CANVAS, errors: { note: 'Too long' } } });
|
|
89
|
+
await userEvent.click(screen.getByRole('button', { name: 'Buy now' }));
|
|
90
|
+
await waitFor(() => {
|
|
91
|
+
expect(screen.getByText('Too long')).toBeDefined();
|
|
92
|
+
});
|
|
93
|
+
// The form is still usable: the field is still there to fix.
|
|
94
|
+
expect(screen.getByLabelText('Gift note')).toBeDefined();
|
|
95
|
+
});
|
|
96
|
+
it('hands a hostEvent on the answer to the APP', async () => {
|
|
97
|
+
// 3-D Secure. The step asks; the app runs it natively.
|
|
98
|
+
const onAction = vi.fn();
|
|
99
|
+
harness({
|
|
100
|
+
answer: {
|
|
101
|
+
canvas: CANVAS,
|
|
102
|
+
errors: {},
|
|
103
|
+
hostEvent: { event: 'confirm_payment', data: { pi: 'pi_1' } },
|
|
104
|
+
},
|
|
105
|
+
onAction,
|
|
106
|
+
});
|
|
107
|
+
await userEvent.click(screen.getByRole('button', { name: 'Buy now' }));
|
|
108
|
+
await waitFor(() => {
|
|
109
|
+
expect(onAction).toHaveBeenCalledWith({
|
|
110
|
+
event: 'confirm_payment',
|
|
111
|
+
data: { pi: 'pi_1' },
|
|
112
|
+
conversationId: CONV,
|
|
113
|
+
messageId: 'm1',
|
|
114
|
+
actionId: 'confirm',
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
it('leaves the form usable when the submission never lands', async () => {
|
|
119
|
+
harness({ reject: true });
|
|
120
|
+
await userEvent.click(screen.getByRole('button', { name: 'Buy now' }));
|
|
121
|
+
await waitFor(() => {
|
|
122
|
+
expect(screen.getByText('That did not go through. Try again.')).toBeDefined();
|
|
123
|
+
});
|
|
124
|
+
// Re-enabled, not stuck on the in-flight state: the shopper can retry and
|
|
125
|
+
// the server is the only thing that can settle the price.
|
|
126
|
+
expect(screen.getByRole('button', { name: 'Buy now' }).hasAttribute('disabled')).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
it('renders nothing for a canvas with no canvasId', () => {
|
|
129
|
+
// A form with nowhere to post is worse than no form.
|
|
130
|
+
const value = { theme: defaultTheme, rest: {} };
|
|
131
|
+
const { container } = render(_jsx(ChatlyContext.Provider, { value: value, children: _jsx(MessageCanvas, { canvas: { v: 1, fields: [] }, conversationId: CONV, messageId: "m1" }) }));
|
|
132
|
+
expect(container.textContent).toBe('');
|
|
133
|
+
});
|
|
134
|
+
it('explains a Tier 3 app rather than opening a WebView', () => {
|
|
135
|
+
// No sandbox attribute exists in React Native, and a WebView is the thing
|
|
136
|
+
// a native SDK exists to avoid.
|
|
137
|
+
const value = { theme: defaultTheme, rest: {} };
|
|
138
|
+
render(_jsx(ChatlyContext.Provider, { value: value, children: _jsx(MessageCanvas, { canvas: { v: 1, canvasId: 'c1', app: { url: 'https://x.test', title: 'Checkout' } }, conversationId: CONV, messageId: "m1" }) }));
|
|
139
|
+
expect(screen.getByText('Checkout opens outside the chat.')).toBeDefined();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=MessageCanvas.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageCanvas.spec.js","sourceRoot":"","sources":["../../src/components/MessageCanvas.spec.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface MessagesListProps {
|
|
3
|
+
conversationId: string;
|
|
4
|
+
/** Number of messages to load on mount. Defaults to 50. */
|
|
5
|
+
pageSize?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function MessagesList({ conversationId, pageSize, }: MessagesListProps): React.JSX.Element;
|
|
8
|
+
//# sourceMappingURL=MessagesList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagesList.d.ts","sourceRoot":"","sources":["../../src/components/MessagesList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAQjF,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,YAAY,CAAC,EAC3B,cAAc,EACd,QAAa,GACd,EAAE,iBAAiB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA0EvC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { FlatList, StyleSheet, View } from 'react-native';
|
|
4
|
+
import { MessageBubble } from './MessageBubble';
|
|
5
|
+
import { useChatly } from '../useChatly';
|
|
6
|
+
export function MessagesList({ conversationId, pageSize = 50, }) {
|
|
7
|
+
const { rest, realtime, theme } = useChatly();
|
|
8
|
+
const [messages, setMessages] = useState([]);
|
|
9
|
+
const listRef = useRef(null);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
let cancelled = false;
|
|
12
|
+
void rest
|
|
13
|
+
.listMessages(conversationId, pageSize)
|
|
14
|
+
.then((res) => {
|
|
15
|
+
if (!cancelled) {
|
|
16
|
+
setMessages(res.messages);
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
.catch(() => undefined);
|
|
20
|
+
return () => {
|
|
21
|
+
cancelled = true;
|
|
22
|
+
};
|
|
23
|
+
}, [rest, conversationId, pageSize]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const off = realtime.on('message.created', (envelope) => {
|
|
26
|
+
const p = envelope.payload;
|
|
27
|
+
if (p.conversationId !== conversationId) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const row = {
|
|
31
|
+
id: p.id,
|
|
32
|
+
authorType: p.authorType,
|
|
33
|
+
kind: 'text',
|
|
34
|
+
body: p.body,
|
|
35
|
+
createdAt: p.createdAt,
|
|
36
|
+
};
|
|
37
|
+
setMessages((prev) => (prev.some((m) => m.id === row.id) ? prev : [...prev, row]));
|
|
38
|
+
});
|
|
39
|
+
return off;
|
|
40
|
+
}, [realtime, conversationId]);
|
|
41
|
+
const data = useMemo(() => [...messages].sort((a, b) => a.createdAt.localeCompare(b.createdAt)), [messages]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (data.length > 0) {
|
|
44
|
+
// Defer until after layout to ensure offset is valid.
|
|
45
|
+
requestAnimationFrame(() => listRef.current?.scrollToEnd({ animated: true }));
|
|
46
|
+
}
|
|
47
|
+
}, [data.length]);
|
|
48
|
+
const renderItem = useCallback(
|
|
49
|
+
// `conversationId` passed down so a card action knows where to report —
|
|
50
|
+
// without it a `host_event` tap would reach the app with a null
|
|
51
|
+
// conversation and `reportAction` would have nowhere to go.
|
|
52
|
+
({ item }) => (_jsx(MessageBubble, { message: item, conversationId: conversationId })), [conversationId]);
|
|
53
|
+
return (_jsx(View, { style: [styles.container, { backgroundColor: theme.colors.background }], children: _jsx(FlatList, { ref: listRef, data: data, keyExtractor: (m) => m.id, renderItem: renderItem, contentContainerStyle: { padding: theme.spacing.md } }) }));
|
|
54
|
+
}
|
|
55
|
+
const styles = StyleSheet.create({
|
|
56
|
+
container: { flex: 1 },
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=MessagesList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagesList.js","sourceRoot":"","sources":["../../src/components/MessagesList.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point for `@chatlychat/react-native`.
|
|
3
|
+
*
|
|
4
|
+
* Everything callers should depend on is re-exported here. Anything not
|
|
5
|
+
* exported is considered an internal implementation detail and may change.
|
|
6
|
+
*/
|
|
7
|
+
export { ChatlyProvider, ChatlyContext } from './ChatlyProvider';
|
|
8
|
+
export type { ChatlyActionEvent, ChatlyProviderProps, ChatlyContextValue } from './ChatlyProvider';
|
|
9
|
+
export { useChatly } from './useChatly';
|
|
10
|
+
export { ChatlyWidget } from './ChatlyWidget';
|
|
11
|
+
export type { ChatlyWidgetProps } from './ChatlyWidget';
|
|
12
|
+
export { MessagesList } from './components/MessagesList';
|
|
13
|
+
export type { MessagesListProps } from './components/MessagesList';
|
|
14
|
+
export { Composer } from './components/Composer';
|
|
15
|
+
export type { ComposerProps } from './components/Composer';
|
|
16
|
+
export { MessageBubble } from './components/MessageBubble';
|
|
17
|
+
export type { MessageBubbleProps } from './components/MessageBubble';
|
|
18
|
+
export { MessageBlocks } from './components/MessageBlocks';
|
|
19
|
+
export type { MessageBlocksProps } from './components/MessageBlocks';
|
|
20
|
+
export { MessageCanvas } from './components/MessageCanvas';
|
|
21
|
+
export type { MessageCanvasProps } from './components/MessageCanvas';
|
|
22
|
+
/**
|
|
23
|
+
* The block vocabulary and its READER, exported.
|
|
24
|
+
*
|
|
25
|
+
* A consumer who wants their own card design — a real markdown renderer, a
|
|
26
|
+
* native clipboard, a video player — renders from the envelope themselves
|
|
27
|
+
* rather than forking the component. `readBlocksEnvelope` is what makes that
|
|
28
|
+
* safe: it is the same refusal the server-side renderers apply, so a custom
|
|
29
|
+
* renderer cannot accidentally draw something the rest of the product would
|
|
30
|
+
* reject.
|
|
31
|
+
*/
|
|
32
|
+
export { readBlocksEnvelope, readCanvas, isSafeMediaSrc } from './blocks/read-envelope';
|
|
33
|
+
export { formatMoney, moneyToPlainText, readMoney } from './blocks/money';
|
|
34
|
+
export { BLOCK_PROTOCOL_VERSION } from './blocks/types';
|
|
35
|
+
export type { Money } from './blocks/money';
|
|
36
|
+
export type { CanvasAction, CanvasField, WidgetAction, WidgetBlock, WidgetBlocksEnvelope, WidgetCanvas, WidgetCard, } from './blocks/types';
|
|
37
|
+
export { HelpCenter } from './components/HelpCenter';
|
|
38
|
+
export type { HelpCenterProps } from './components/HelpCenter';
|
|
39
|
+
export { RestClient } from './client/RestClient';
|
|
40
|
+
export { RealtimeClient } from './client/RealtimeClient';
|
|
41
|
+
export { IdentityStore, TokenStore } from './storage/TokenStore';
|
|
42
|
+
export type { StoredIdentity } from './storage/TokenStore';
|
|
43
|
+
export { registerPushToken } from './push/registerPushToken';
|
|
44
|
+
export { defaultTheme } from './theme/defaultTheme';
|
|
45
|
+
export type { ChatlyTheme } from './theme/ChatlyTheme';
|
|
46
|
+
export type { Attachment, ChatlyConfig, ChatlyIdentity, ConversationStatus, ConversationSummary, InitResponse, KbArticle, KbResult, MessageAuthor, MessageCreatedPayload, MessageKind, MessageRow, PushPlatform, PushTokenRegistration, RealtimeEnvelope, RealtimeEventType, SessionState, StartResponse, } from './client/types';
|
|
47
|
+
export { REALTIME_PROTOCOL_VERSION } from './client/types';
|
|
48
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE;;;;;;;;;GASG;AACH,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,YAAY,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,YAAY,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACjE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,YAAY,EACV,UAAU,EACV,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,aAAa,EACb,qBAAqB,EACrB,WAAW,EACX,UAAU,EACV,YAAY,EACZ,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point for `@chatlychat/react-native`.
|
|
3
|
+
*
|
|
4
|
+
* Everything callers should depend on is re-exported here. Anything not
|
|
5
|
+
* exported is considered an internal implementation detail and may change.
|
|
6
|
+
*/
|
|
7
|
+
export { ChatlyProvider, ChatlyContext } from './ChatlyProvider';
|
|
8
|
+
export { useChatly } from './useChatly';
|
|
9
|
+
export { ChatlyWidget } from './ChatlyWidget';
|
|
10
|
+
export { MessagesList } from './components/MessagesList';
|
|
11
|
+
export { Composer } from './components/Composer';
|
|
12
|
+
export { MessageBubble } from './components/MessageBubble';
|
|
13
|
+
export { MessageBlocks } from './components/MessageBlocks';
|
|
14
|
+
export { MessageCanvas } from './components/MessageCanvas';
|
|
15
|
+
/**
|
|
16
|
+
* The block vocabulary and its READER, exported.
|
|
17
|
+
*
|
|
18
|
+
* A consumer who wants their own card design — a real markdown renderer, a
|
|
19
|
+
* native clipboard, a video player — renders from the envelope themselves
|
|
20
|
+
* rather than forking the component. `readBlocksEnvelope` is what makes that
|
|
21
|
+
* safe: it is the same refusal the server-side renderers apply, so a custom
|
|
22
|
+
* renderer cannot accidentally draw something the rest of the product would
|
|
23
|
+
* reject.
|
|
24
|
+
*/
|
|
25
|
+
export { readBlocksEnvelope, readCanvas, isSafeMediaSrc } from './blocks/read-envelope';
|
|
26
|
+
export { formatMoney, moneyToPlainText, readMoney } from './blocks/money';
|
|
27
|
+
export { BLOCK_PROTOCOL_VERSION } from './blocks/types';
|
|
28
|
+
export { HelpCenter } from './components/HelpCenter';
|
|
29
|
+
export { RestClient } from './client/RestClient';
|
|
30
|
+
export { RealtimeClient } from './client/RealtimeClient';
|
|
31
|
+
export { IdentityStore, TokenStore } from './storage/TokenStore';
|
|
32
|
+
export { registerPushToken } from './push/registerPushToken';
|
|
33
|
+
export { defaultTheme } from './theme/defaultTheme';
|
|
34
|
+
export { REALTIME_PROTOCOL_VERSION } from './client/types';
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D;;;;;;;;;GASG;AACH,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAYxD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGrD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAuBpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register a mobile push token (APNS / FCM) against the current widget
|
|
3
|
+
* visitor session. Routes to the public `/v1/widget/push/register` endpoint
|
|
4
|
+
* which the API exposes for SDK consumers.
|
|
5
|
+
*
|
|
6
|
+
* The RestClient maintains the `publicId` + `visitorToken` it persisted at
|
|
7
|
+
* init time, so the caller only needs to provide `{ platform, token }`.
|
|
8
|
+
*/
|
|
9
|
+
import type { RestClient } from '../client/RestClient';
|
|
10
|
+
import type { ChatlyIdentity, PushTokenRegistration } from '../client/types';
|
|
11
|
+
export declare function registerPushToken(rest: RestClient, registration: PushTokenRegistration, _identity?: ChatlyIdentity): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=registerPushToken.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registerPushToken.d.ts","sourceRoot":"","sources":["../../src/push/registerPushToken.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAgB,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAmB3F,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,UAAU,EAChB,YAAY,EAAE,qBAAqB,EACnC,SAAS,CAAC,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC,CAMf"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register a mobile push token (APNS / FCM) against the current widget
|
|
3
|
+
* visitor session. Routes to the public `/v1/widget/push/register` endpoint
|
|
4
|
+
* which the API exposes for SDK consumers.
|
|
5
|
+
*
|
|
6
|
+
* The RestClient maintains the `publicId` + `visitorToken` it persisted at
|
|
7
|
+
* init time, so the caller only needs to provide `{ platform, token }`.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Translate the SDK-facing platform vocab into the server's transport vocab.
|
|
11
|
+
* iOS native → APNS
|
|
12
|
+
* Android native → FCM
|
|
13
|
+
* Expo → FCM (Expo's push service tokenizes upstream to FCM/APNS,
|
|
14
|
+
* but the device-side token we receive is an Expo push
|
|
15
|
+
* token; the API service routes it via FCM-compatible
|
|
16
|
+
* delivery)
|
|
17
|
+
*/
|
|
18
|
+
function toServerPlatform(p) {
|
|
19
|
+
if (p === 'ios') {
|
|
20
|
+
return 'apns';
|
|
21
|
+
}
|
|
22
|
+
// 'android' and 'expo' both route through the FCM-compatible path
|
|
23
|
+
return 'fcm';
|
|
24
|
+
}
|
|
25
|
+
export async function registerPushToken(rest, registration, _identity) {
|
|
26
|
+
await rest.registerPushToken({
|
|
27
|
+
platform: toServerPlatform(registration.platform),
|
|
28
|
+
token: registration.token,
|
|
29
|
+
...(registration.appVersion !== undefined ? { appVersion: registration.appVersion } : {}),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=registerPushToken.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registerPushToken.js","sourceRoot":"","sources":["../../src/push/registerPushToken.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH;;;;;;;;GAQG;AACH,SAAS,gBAAgB,CAAC,CAAe;IACvC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC;QAChB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,kEAAkE;IAClE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAgB,EAChB,YAAmC,EACnC,SAA0B;IAE1B,MAAM,IAAI,CAAC,iBAAiB,CAAC;QAC3B,QAAQ,EAAE,gBAAgB,CAAC,YAAY,CAAC,QAAQ,CAAC;QACjD,KAAK,EAAE,YAAY,CAAC,KAAK;QACzB,GAAG,CAAC,YAAY,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,YAAY,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1F,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent storage for the visitor token. Mirrors the browser SDK's
|
|
3
|
+
* `localStorage` key convention so a hand-off between web and mobile sessions
|
|
4
|
+
* could in principle reuse the same identifier shape: `chatly:vt:${publicId}`.
|
|
5
|
+
*
|
|
6
|
+
* Uses `@react-native-async-storage/async-storage` (peer dependency). We
|
|
7
|
+
* intentionally require it lazily so the SDK does not crash at import time
|
|
8
|
+
* if the host app forgot to install it — instead we throw a clear error
|
|
9
|
+
* when the token store is first used.
|
|
10
|
+
*/
|
|
11
|
+
export declare class TokenStore {
|
|
12
|
+
private readonly key;
|
|
13
|
+
constructor(publicId: string);
|
|
14
|
+
get(): Promise<string | null>;
|
|
15
|
+
set(value: string): Promise<void>;
|
|
16
|
+
clear(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Persistent store for the identity this device last successfully asserted.
|
|
20
|
+
*
|
|
21
|
+
* Kept for the same reason the browser widget keeps `chatly:xid:` /
|
|
22
|
+
* `chatly:vh:`: the visitor token is now an opaque signed credential rather
|
|
23
|
+
* than the external id itself, so when the server refuses a stale token this
|
|
24
|
+
* is the only way the SDK can re-assert who the host app said this person was
|
|
25
|
+
* without waiting for the app to call `identify()` again. Conversation history
|
|
26
|
+
* hangs off the contact, so replaying the identity brings all of it back.
|
|
27
|
+
*
|
|
28
|
+
* Only ever holds an identity the SERVER ACCEPTED (see `RestClient.init`) —
|
|
29
|
+
* remembering a rejected hash would replay it on every subsequent request and
|
|
30
|
+
* turn one 403 into a permanently broken SDK.
|
|
31
|
+
*
|
|
32
|
+
* Not a secret: the host app put it here, and `userHash` is an HMAC of a value
|
|
33
|
+
* the host app already knows.
|
|
34
|
+
*/
|
|
35
|
+
export declare class IdentityStore {
|
|
36
|
+
private readonly key;
|
|
37
|
+
constructor(publicId: string);
|
|
38
|
+
get(): Promise<StoredIdentity | null>;
|
|
39
|
+
set(value: StoredIdentity): Promise<void>;
|
|
40
|
+
clear(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Structurally the SDK's `ChatlyIdentity`, restated here so `storage/` does
|
|
44
|
+
* not depend on `client/` (the dependency runs the other way).
|
|
45
|
+
*/
|
|
46
|
+
export interface StoredIdentity {
|
|
47
|
+
externalId: string;
|
|
48
|
+
email?: string;
|
|
49
|
+
name?: string;
|
|
50
|
+
userHash?: string;
|
|
51
|
+
attributes?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=TokenStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenStore.d.ts","sourceRoot":"","sources":["../../src/storage/TokenStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkCH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEV,QAAQ,EAAE,MAAM;IAItB,GAAG,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI7B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGpC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEV,QAAQ,EAAE,MAAM;IAItB,GAAG,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAerC,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGpC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent storage for the visitor token. Mirrors the browser SDK's
|
|
3
|
+
* `localStorage` key convention so a hand-off between web and mobile sessions
|
|
4
|
+
* could in principle reuse the same identifier shape: `chatly:vt:${publicId}`.
|
|
5
|
+
*
|
|
6
|
+
* Uses `@react-native-async-storage/async-storage` (peer dependency). We
|
|
7
|
+
* intentionally require it lazily so the SDK does not crash at import time
|
|
8
|
+
* if the host app forgot to install it — instead we throw a clear error
|
|
9
|
+
* when the token store is first used.
|
|
10
|
+
*/
|
|
11
|
+
let cachedStorage = null;
|
|
12
|
+
function getStorage() {
|
|
13
|
+
if (cachedStorage !== null) {
|
|
14
|
+
return cachedStorage;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- RN peer-dep loaded lazily.
|
|
18
|
+
const mod = require('@react-native-async-storage/async-storage');
|
|
19
|
+
const storage = mod.default ?? mod;
|
|
20
|
+
if (typeof storage.getItem !== 'function') {
|
|
21
|
+
throw new Error('module loaded but does not expose getItem');
|
|
22
|
+
}
|
|
23
|
+
cachedStorage = storage;
|
|
24
|
+
return storage;
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
throw new Error('[@chatlychat/react-native] @react-native-async-storage/async-storage is required. ' +
|
|
28
|
+
'Install it in your app: `npm install @react-native-async-storage/async-storage`. ' +
|
|
29
|
+
`Underlying error: ${err.message}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export class TokenStore {
|
|
33
|
+
constructor(publicId) {
|
|
34
|
+
this.key = `chatly:vt:${publicId}`;
|
|
35
|
+
}
|
|
36
|
+
async get() {
|
|
37
|
+
return getStorage().getItem(this.key);
|
|
38
|
+
}
|
|
39
|
+
async set(value) {
|
|
40
|
+
await getStorage().setItem(this.key, value);
|
|
41
|
+
}
|
|
42
|
+
async clear() {
|
|
43
|
+
await getStorage().removeItem(this.key);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Persistent store for the identity this device last successfully asserted.
|
|
48
|
+
*
|
|
49
|
+
* Kept for the same reason the browser widget keeps `chatly:xid:` /
|
|
50
|
+
* `chatly:vh:`: the visitor token is now an opaque signed credential rather
|
|
51
|
+
* than the external id itself, so when the server refuses a stale token this
|
|
52
|
+
* is the only way the SDK can re-assert who the host app said this person was
|
|
53
|
+
* without waiting for the app to call `identify()` again. Conversation history
|
|
54
|
+
* hangs off the contact, so replaying the identity brings all of it back.
|
|
55
|
+
*
|
|
56
|
+
* Only ever holds an identity the SERVER ACCEPTED (see `RestClient.init`) —
|
|
57
|
+
* remembering a rejected hash would replay it on every subsequent request and
|
|
58
|
+
* turn one 403 into a permanently broken SDK.
|
|
59
|
+
*
|
|
60
|
+
* Not a secret: the host app put it here, and `userHash` is an HMAC of a value
|
|
61
|
+
* the host app already knows.
|
|
62
|
+
*/
|
|
63
|
+
export class IdentityStore {
|
|
64
|
+
constructor(publicId) {
|
|
65
|
+
this.key = `chatly:id:${publicId}`;
|
|
66
|
+
}
|
|
67
|
+
async get() {
|
|
68
|
+
const raw = await getStorage().getItem(this.key);
|
|
69
|
+
if (raw === null) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const parsed = JSON.parse(raw);
|
|
74
|
+
return typeof parsed?.externalId === 'string' ? parsed : null;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// A corrupt entry is indistinguishable from no entry as far as the
|
|
78
|
+
// caller is concerned: re-init anonymously rather than throwing.
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async set(value) {
|
|
83
|
+
await getStorage().setItem(this.key, JSON.stringify(value));
|
|
84
|
+
}
|
|
85
|
+
async clear() {
|
|
86
|
+
await getStorage().removeItem(this.key);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=TokenStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenStore.js","sourceRoot":"","sources":["../../src/storage/TokenStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,IAAI,aAAa,GAA4B,IAAI,CAAC;AAElD,SAAS,UAAU;IACjB,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,IAAI,CAAC;QACH,+FAA+F;QAC/F,MAAM,GAAG,GAAG,OAAO,CAAC,2CAA2C,CAElC,CAAC;QAC9B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAK,GAAmC,CAAC;QACpE,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QACD,aAAa,GAAG,OAAO,CAAC;QACxB,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,oFAAoF;YAClF,mFAAmF;YACnF,qBAAsB,GAAa,CAAC,OAAO,EAAE,CAChD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,OAAO,UAAU;IAGrB,YAAmB,QAAgB;QACjC,IAAI,CAAC,GAAG,GAAG,aAAa,QAAQ,EAAE,CAAC;IACrC,CAAC;IAEM,KAAK,CAAC,GAAG;QACd,OAAO,UAAU,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC;IAEM,KAAK,CAAC,GAAG,CAAC,KAAa;QAC5B,MAAM,UAAU,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IAEM,KAAK,CAAC,KAAK;QAChB,MAAM,UAAU,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC;CACF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,aAAa;IAGxB,YAAmB,QAAgB;QACjC,IAAI,CAAC,GAAG,GAAG,aAAa,QAAQ,EAAE,CAAC;IACrC,CAAC;IAEM,KAAK,CAAC,GAAG;QACd,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;YACjD,OAAO,OAAO,MAAM,EAAE,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;YACnE,iEAAiE;YACjE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,GAAG,CAAC,KAAqB;QACpC,MAAM,UAAU,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,CAAC;IAEM,KAAK,CAAC,KAAK;QAChB,MAAM,UAAU,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC;CACF"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DOM stand-in for the React Native primitives THIS package uses, so its
|
|
3
|
+
* components can be tested at all.
|
|
4
|
+
*
|
|
5
|
+
* ── Why this package needed one ────────────────────────────────────────
|
|
6
|
+
*
|
|
7
|
+
* `vitest.config.ts` here included `src/**/*.spec.ts`, which cannot match a
|
|
8
|
+
* `.tsx` file — so every component in a published SDK (the composer, the
|
|
9
|
+
* message list, and now the block and canvas renderers a shopper taps) was
|
|
10
|
+
* structurally untestable. The same one-line config bug that left
|
|
11
|
+
* `apps/mobile-agent`'s screens uncovered, in a package customers ship.
|
|
12
|
+
*
|
|
13
|
+
* ── Why it is a second stand-in and not a shared one ───────────────────
|
|
14
|
+
*
|
|
15
|
+
* `apps/mobile-agent/src/test/react-native-mock.tsx` is the same idea for the
|
|
16
|
+
* agent app, and sharing them was tried and reverted. The only place a
|
|
17
|
+
* workspace-shared version could live is `@livechat/testing`, which depends
|
|
18
|
+
* on `@livechat/db`, `postgres` and `testcontainers` — so every React Native
|
|
19
|
+
* package would take a Postgres driver into its dev graph to borrow a `<div>`
|
|
20
|
+
* wrapper, and a bare `@livechat/testing/react-native-dom` specifier does not
|
|
21
|
+
* resolve from an app that does not depend on it. The two files also cover
|
|
22
|
+
* genuinely different sets: that one has `Alert`, `Modal`, `Switch`,
|
|
23
|
+
* `Animated` and a navigation stub; this one has the twelve primitives this
|
|
24
|
+
* package imports and nothing else.
|
|
25
|
+
*
|
|
26
|
+
* The real risk of a local copy is not drift — neither file is a contract —
|
|
27
|
+
* it is a stand-in that silently lacks a primitive a component starts using,
|
|
28
|
+
* which makes that component untestable again. `react-native-dom.spec.tsx`
|
|
29
|
+
* reads every `from 'react-native'` import in this package's source and
|
|
30
|
+
* fails if any name is missing from here, which is the half that matters.
|
|
31
|
+
*
|
|
32
|
+
* ── What it does NOT prove ─────────────────────────────────────────────
|
|
33
|
+
*
|
|
34
|
+
* Nothing native: not layout, not gestures, not keyboard behaviour, not that
|
|
35
|
+
* a `Pressable` has a large enough hit area, not that the package builds for
|
|
36
|
+
* a device. What it covers is the React layer, which is where component bugs
|
|
37
|
+
* are.
|
|
38
|
+
*
|
|
39
|
+
* `accessibilityLabel` becomes `aria-label` and `testID` becomes
|
|
40
|
+
* `data-testid`, deliberately: a test then asks for an element the way a
|
|
41
|
+
* screen reader would, so a control that is unlabelled in the app is also
|
|
42
|
+
* unfindable in the test.
|
|
43
|
+
*/
|
|
44
|
+
import React from 'react';
|
|
45
|
+
type AnyProps = Record<string, unknown> & {
|
|
46
|
+
children?: React.ReactNode;
|
|
47
|
+
};
|
|
48
|
+
export declare const View: (props: AnyProps) => React.DetailedReactHTMLElement<Record<string, unknown>, HTMLElement>;
|
|
49
|
+
export declare const SafeAreaView: (props: AnyProps) => React.DetailedReactHTMLElement<Record<string, unknown>, HTMLElement>;
|
|
50
|
+
export declare const ScrollView: (props: AnyProps) => React.DetailedReactHTMLElement<Record<string, unknown>, HTMLElement>;
|
|
51
|
+
export declare const Text: (props: AnyProps) => React.DetailedReactHTMLElement<Record<string, unknown>, HTMLElement>;
|
|
52
|
+
export declare const ActivityIndicator: (props: AnyProps) => React.DetailedReactHTMLElement<Record<string, unknown>, HTMLElement>;
|
|
53
|
+
export declare const Image: (props: AnyProps) => React.ReactElement<{
|
|
54
|
+
src: string;
|
|
55
|
+
alt: string;
|
|
56
|
+
}, string | React.JSXElementConstructor<any>>;
|
|
57
|
+
export declare const Pressable: (props: AnyProps) => React.DetailedReactHTMLElement<{
|
|
58
|
+
type: string;
|
|
59
|
+
onClick: (() => void) | undefined;
|
|
60
|
+
}, HTMLElement>;
|
|
61
|
+
export declare const TouchableOpacity: (props: AnyProps) => React.DetailedReactHTMLElement<{
|
|
62
|
+
type: string;
|
|
63
|
+
onClick: (() => void) | undefined;
|
|
64
|
+
}, HTMLElement>;
|
|
65
|
+
export declare const TextInput: (props: AnyProps) => React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
|
66
|
+
/**
|
|
67
|
+
* `FlatList` rendered eagerly, every row.
|
|
68
|
+
*
|
|
69
|
+
* A virtualising list would render a window, and a test asserting "the row is
|
|
70
|
+
* there" would then depend on a measured viewport that jsdom does not have.
|
|
71
|
+
* Every row is the honest simplification: it can over-report (a row present
|
|
72
|
+
* here might be off-screen on a device) and it cannot under-report, which is
|
|
73
|
+
* the direction a test should fail in.
|
|
74
|
+
*/
|
|
75
|
+
export declare const FlatList: (props: AnyProps) => React.DetailedReactHTMLElement<Record<string, unknown>, HTMLElement>;
|
|
76
|
+
export type ListRenderItemInfo<T> = {
|
|
77
|
+
item: T;
|
|
78
|
+
index: number;
|
|
79
|
+
};
|
|
80
|
+
export declare const Platform: {
|
|
81
|
+
OS: "ios";
|
|
82
|
+
select: (o: Record<string, unknown>) => unknown;
|
|
83
|
+
};
|
|
84
|
+
export declare const StyleSheet: {
|
|
85
|
+
create: <T>(styles: T) => T;
|
|
86
|
+
hairlineWidth: number;
|
|
87
|
+
flatten: (s: unknown) => unknown;
|
|
88
|
+
absoluteFill: {};
|
|
89
|
+
};
|
|
90
|
+
/** Opening a url. Recorded rather than performed, so a test can assert it. */
|
|
91
|
+
export declare const openedUrls: string[];
|
|
92
|
+
export declare const Linking: {
|
|
93
|
+
openURL: (url: string) => Promise<void>;
|
|
94
|
+
canOpenURL: () => Promise<boolean>;
|
|
95
|
+
};
|
|
96
|
+
export {};
|
|
97
|
+
//# sourceMappingURL=react-native-dom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native-dom.d.ts","sourceRoot":"","sources":["../../src/test/react-native-dom.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAAC;AAmCzE,eAAO,MAAM,IAAI,UALa,QAAQ,yEAKP,CAAC;AAChC,eAAO,MAAM,YAAY,UANK,QAAQ,yEAMC,CAAC;AACxC,eAAO,MAAM,UAAU,UAPO,QAAQ,yEAOD,CAAC;AACtC,eAAO,MAAM,IAAI,UARa,QAAQ,yEAQN,CAAC;AAEjC,eAAO,MAAM,iBAAiB,UAAqC,QAAQ,yEAE1E,CAAC;AAEF,eAAO,MAAM,KAAK,UAAyB,QAAQ;;;6CASlD,CAAC;AAqBF,eAAO,MAAM,SAAS,UAZsB,QAAQ;;oBAOa,IAAI;eAKnC,CAAC;AACnC,eAAO,MAAM,gBAAgB,UAbe,QAAQ;;oBAOa,IAAI;eAM5B,CAAC;AAE1C,eAAO,MAAM,SAAS,UAA6B,QAAQ,kGAY1D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,UAA4B,QAAQ,yEAqBxD,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,eAAO,MAAM,QAAQ;;gBAAqC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAAe,CAAC;AAEjG,eAAO,MAAM,UAAU;aACZ,CAAC,UAAW,CAAC,KAAG,CAAC;;iBAEb,OAAO;;CAErB,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,UAAU,EAAE,MAAM,EAAO,CAAC;AACvC,eAAO,MAAM,OAAO;mBACG,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;sBAGrB,OAAO,CAAC,OAAO,CAAC;CACvC,CAAC"}
|