@dynamic-labs/react-native-extension 4.0.0-alpha.2 → 4.0.0-alpha.20

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