@dynamic-labs/react-native-extension 4.0.0-alpha.4 → 4.0.0-alpha.5

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.
Files changed (3) hide show
  1. package/index.cjs +121 -2879
  2. package/index.js +281 -0
  3. package/package.json +8 -8
package/index.js ADDED
@@ -0,0 +1,281 @@
1
+ import { useRef, useEffect, useCallback, useState } from 'react';
2
+ import { WebView as WebView$1 } from 'react-native-webview';
3
+ import { parseMessageTransportData, createRequestChannel } from '@dynamic-labs/message-transport';
4
+ import { Logger } from '@dynamic-labs/logger';
5
+ import { StyleSheet } from 'react-native';
6
+ import { jsx } from 'react/jsx-runtime';
7
+ import { createPasskey, PasskeyStamper } from '@turnkey/react-native-passkey-stamper';
8
+ import { createURL, openURL } from 'expo-linking';
9
+ import { openAuthSessionAsync } from 'expo-web-browser';
10
+ import { getItemAsync, setItemAsync, deleteItemAsync } from 'expo-secure-store';
11
+
12
+ var version = "4.0.0-alpha.5";
13
+
14
+ function _extends() {
15
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
16
+ for (var i = 1; i < arguments.length; i++) {
17
+ var source = arguments[i];
18
+ for (var key in source) {
19
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
20
+ target[key] = source[key];
21
+ }
22
+ }
23
+ }
24
+ return target;
25
+ };
26
+ return _extends.apply(this, arguments);
27
+ }
28
+
29
+ const logger = new Logger('react-native-extension');
30
+
31
+ const useIsMounted = () => {
32
+ const isMountedRef = useRef(true);
33
+ useEffect(() => () => {
34
+ isMountedRef.current = false;
35
+ }, []);
36
+ return useCallback(() => isMountedRef.current, [isMountedRef]);
37
+ };
38
+
39
+ const useMessageTransportWebViewBridge = (core, webViewRef) => {
40
+ const canBroadcastMessages = useIsMounted();
41
+ /**
42
+ * Receive a message from the webview and forward it to the client
43
+ * message transport
44
+ */
45
+ const onMessageHandler = event => {
46
+ if (!canBroadcastMessages()) return;
47
+ let parsedData = null;
48
+ try {
49
+ parsedData = JSON.parse(event.nativeEvent.data);
50
+ } catch (err) {
51
+ logger.debug('error parsing data', err);
52
+ return;
53
+ }
54
+ const message = parseMessageTransportData(parsedData);
55
+ if (!message) {
56
+ logger.debug('invalid message', message);
57
+ return;
58
+ }
59
+ /**
60
+ * Only forward messages from the created by the webview
61
+ */
62
+ if (message.origin === 'webview') {
63
+ core.messageTransport.emit(message);
64
+ }
65
+ };
66
+ /**
67
+ * Send messages created by the client to the webview
68
+ */
69
+ useEffect(() => {
70
+ const sendMessageToWebView = message => {
71
+ if (!canBroadcastMessages()) return;
72
+ /**
73
+ * Only forward messages to the webview
74
+ * that where created by the client/host
75
+ */
76
+ if (message.origin === 'host' && webViewRef.current) {
77
+ webViewRef.current.postMessage(JSON.stringify(message));
78
+ }
79
+ };
80
+ core.messageTransport.on(sendMessageToWebView);
81
+ return () => {
82
+ core.messageTransport.off(sendMessageToWebView);
83
+ };
84
+ }, [core.messageTransport, webViewRef, canBroadcastMessages]);
85
+ return {
86
+ onMessageHandler
87
+ };
88
+ };
89
+
90
+ const useWebViewVisibility = core => {
91
+ const webViewVisibilityRequestChannelRef = useRef(createRequestChannel(core.messageTransport));
92
+ const [visible, setVisible] = useState(false);
93
+ useEffect(() => webViewVisibilityRequestChannelRef.current.handle('setVisibility', setVisible), [setVisible]);
94
+ return {
95
+ visible
96
+ };
97
+ };
98
+
99
+ const styles = StyleSheet.create({
100
+ container: {
101
+ backgroundColor: 'transparent',
102
+ bottom: 0,
103
+ flex: 1,
104
+ left: 0,
105
+ position: 'absolute',
106
+ right: 0,
107
+ top: 0,
108
+ width: '100%'
109
+ },
110
+ hide: {
111
+ elevation: 0,
112
+ opacity: 0,
113
+ zIndex: -10000
114
+ },
115
+ show: {
116
+ elevation: 10000,
117
+ opacity: 1,
118
+ zIndex: 10000
119
+ },
120
+ webview: {
121
+ backgroundColor: 'transparent',
122
+ flex: 1
123
+ }
124
+ });
125
+
126
+ const WebView = ({
127
+ webviewUrl,
128
+ core,
129
+ webviewDebuggingEnabled: _webviewDebuggingEnabled = false
130
+ }) => {
131
+ const webViewRef = useRef(null);
132
+ const {
133
+ visible
134
+ } = useWebViewVisibility(core);
135
+ const {
136
+ onMessageHandler
137
+ } = useMessageTransportWebViewBridge(core, webViewRef);
138
+ const containerStyles = [styles['container'], visible ? styles.show : styles.hide];
139
+ return /*#__PURE__*/jsx(WebView$1, {
140
+ ref: webViewRef,
141
+ source: {
142
+ uri: webviewUrl
143
+ },
144
+ containerStyle: containerStyles,
145
+ style: styles['webview'],
146
+ onMessage: onMessageHandler,
147
+ hideKeyboardAccessoryView: true,
148
+ webviewDebuggingEnabled: _webviewDebuggingEnabled,
149
+ onError: () => core.initialization.error = new Error('Could not load Dynamic WebView')
150
+ }, 'webview');
151
+ };
152
+ const createWebView = props => {
153
+ const WebViewWrapper = () => /*#__PURE__*/jsx(WebView, _extends({}, props));
154
+ return WebViewWrapper;
155
+ };
156
+
157
+ /******************************************************************************
158
+ Copyright (c) Microsoft Corporation.
159
+
160
+ Permission to use, copy, modify, and/or distribute this software for any
161
+ purpose with or without fee is hereby granted.
162
+
163
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
164
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
165
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
166
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
167
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
168
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
169
+ PERFORMANCE OF THIS SOFTWARE.
170
+ ***************************************************************************** */
171
+
172
+ function __awaiter(thisArg, _arguments, P, generator) {
173
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
174
+ return new (P || (P = Promise))(function (resolve, reject) {
175
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
176
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
177
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
178
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
179
+ });
180
+ }
181
+
182
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
183
+ var e = new Error(message);
184
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
185
+ };
186
+
187
+ const setupFetchHandler = core => {
188
+ const fetchRequestChannel = createRequestChannel(core.messageTransport);
189
+ fetchRequestChannel.handle('fetch', (input, init) => __awaiter(void 0, void 0, void 0, function* () {
190
+ const response = yield fetch(input, init);
191
+ const responseBody = yield response.text();
192
+ return {
193
+ body: responseBody,
194
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
195
+ headers: Object.fromEntries(response.headers.entries()),
196
+ status: response.status,
197
+ statusText: response.statusText
198
+ };
199
+ }));
200
+ };
201
+
202
+ const setupPasskeyHandler = core => {
203
+ const passkeysRequestChannel = createRequestChannel(core.messageTransport);
204
+ passkeysRequestChannel.handle('createPasskey', _a => __awaiter(void 0, [_a], void 0, function* ({
205
+ publicKey
206
+ }) {
207
+ try {
208
+ const {
209
+ attestation
210
+ } = yield createPasskey(publicKey);
211
+ return {
212
+ attestation
213
+ };
214
+ } catch (err) {
215
+ logger.error(err);
216
+ throw err;
217
+ }
218
+ }));
219
+ passkeysRequestChannel.handle('passkeyStamp', (rpId, payload) => __awaiter(void 0, void 0, void 0, function* () {
220
+ try {
221
+ const stamper = new PasskeyStamper({
222
+ rpId
223
+ });
224
+ const stamped = yield stamper.stamp(payload);
225
+ return stamped;
226
+ } catch (err) {
227
+ logger.error(err);
228
+ throw err;
229
+ }
230
+ }));
231
+ };
232
+
233
+ const setupPlatformHandler = core => {
234
+ const platformChannel = createRequestChannel(core.messageTransport);
235
+ core.manifest.setPlatform('react-native');
236
+ core.manifest.setRedirectUrl(createURL(''));
237
+ platformChannel.handle('openURL', url => __awaiter(void 0, void 0, void 0, function* () {
238
+ yield openURL(url);
239
+ }));
240
+ platformChannel.handle('openAuthenticationWindow', _a => __awaiter(void 0, [_a], void 0, function* ({
241
+ url,
242
+ redirectUrl
243
+ }) {
244
+ const result = yield openAuthSessionAsync(url, redirectUrl);
245
+ // When not a success, result can only have a type which is a string describing
246
+ // what happened in a single word.
247
+ if (result.type !== 'success') throw new Error(result.type);
248
+ return result.url;
249
+ }));
250
+ };
251
+
252
+ const setupSecureStorageHandler = core => {
253
+ const secureStorageRequestChannel = createRequestChannel(core.messageTransport);
254
+ secureStorageRequestChannel.handle('getSecureItem', getItemAsync);
255
+ secureStorageRequestChannel.handle('setSecureItem', setItemAsync);
256
+ secureStorageRequestChannel.handle('deleteSecureItem', deleteItemAsync);
257
+ };
258
+
259
+ const defaultWebviewUrl = `https://webview.dynamicauth.com/${version}`;
260
+ const ReactNativeExtension = ({
261
+ webviewUrl: _webviewUrl = defaultWebviewUrl,
262
+ webviewDebuggingEnabled,
263
+ appOrigin
264
+ } = {}) => (_, core) => {
265
+ if (appOrigin) core.manifest.setAppOrigin(appOrigin);
266
+ setupPasskeyHandler(core);
267
+ setupFetchHandler(core);
268
+ setupPlatformHandler(core);
269
+ setupSecureStorageHandler(core);
270
+ return {
271
+ reactNative: {
272
+ WebView: createWebView({
273
+ core,
274
+ webviewDebuggingEnabled,
275
+ webviewUrl: _webviewUrl
276
+ })
277
+ }
278
+ };
279
+ };
280
+
281
+ export { ReactNativeExtension };
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "name": "@dynamic-labs/react-native-extension",
3
- "version": "4.0.0-alpha.4",
3
+ "version": "4.0.0-alpha.5",
4
4
  "main": "./index.cjs",
5
- "module": "./src/index.js",
5
+ "module": "./index.js",
6
6
  "types": "./src/index.d.ts",
7
- "type": "commonjs",
7
+ "type": "module",
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./src/index.d.ts",
11
- "import": "./src/index.js",
12
- "require": "./src/index.cjs"
11
+ "import": "./index.js",
12
+ "require": "./index.cjs"
13
13
  },
14
14
  "./package.json": "./package.json"
15
15
  },
16
16
  "dependencies": {
17
17
  "@turnkey/react-native-passkey-stamper": "0.2.5",
18
- "@dynamic-labs/client": "4.0.0-alpha.4",
19
- "@dynamic-labs/logger": "4.0.0-alpha.4",
20
- "@dynamic-labs/message-transport": "4.0.0-alpha.4"
18
+ "@dynamic-labs/client": "4.0.0-alpha.5",
19
+ "@dynamic-labs/logger": "4.0.0-alpha.5",
20
+ "@dynamic-labs/message-transport": "4.0.0-alpha.5"
21
21
  },
22
22
  "peerDependencies": {
23
23
  "react": "^18.2.0",