@dynamic-labs/react-native-extension 4.0.0-alpha.1 → 4.0.0-alpha.11

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 +123 -2878
  2. package/index.js +284 -0
  3. package/package.json +9 -8
package/index.js ADDED
@@ -0,0 +1,284 @@
1
+ import { assertPackageVersion } from '@dynamic-labs/assert-package-version';
2
+ import { useRef, useEffect, useCallback, useState } from 'react';
3
+ import { WebView as WebView$1 } from 'react-native-webview';
4
+ import { parseMessageTransportData, createRequestChannel } from '@dynamic-labs/message-transport';
5
+ import { Logger } from '@dynamic-labs/logger';
6
+ import { StyleSheet } from 'react-native';
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, setItemAsync, deleteItemAsync } from 'expo-secure-store';
12
+
13
+ var version = "4.0.0-alpha.11";
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 setupFetchHandler = core => {
189
+ const fetchRequestChannel = createRequestChannel(core.messageTransport);
190
+ fetchRequestChannel.handle('fetch', (input, init) => __awaiter(void 0, void 0, void 0, function* () {
191
+ const response = yield fetch(input, init);
192
+ const responseBody = yield response.text();
193
+ return {
194
+ body: responseBody,
195
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
196
+ headers: Object.fromEntries(response.headers.entries()),
197
+ status: response.status,
198
+ statusText: response.statusText
199
+ };
200
+ }));
201
+ };
202
+
203
+ const setupPasskeyHandler = core => {
204
+ const passkeysRequestChannel = createRequestChannel(core.messageTransport);
205
+ passkeysRequestChannel.handle('createPasskey', _a => __awaiter(void 0, [_a], void 0, function* ({
206
+ publicKey
207
+ }) {
208
+ try {
209
+ const {
210
+ attestation
211
+ } = yield createPasskey(publicKey);
212
+ return {
213
+ attestation
214
+ };
215
+ } catch (err) {
216
+ logger.error(err);
217
+ throw err;
218
+ }
219
+ }));
220
+ passkeysRequestChannel.handle('passkeyStamp', (rpId, payload) => __awaiter(void 0, void 0, void 0, function* () {
221
+ try {
222
+ const stamper = new PasskeyStamper({
223
+ rpId
224
+ });
225
+ const stamped = yield stamper.stamp(payload);
226
+ return stamped;
227
+ } catch (err) {
228
+ logger.error(err);
229
+ throw err;
230
+ }
231
+ }));
232
+ };
233
+
234
+ const setupPlatformHandler = core => {
235
+ const platformChannel = createRequestChannel(core.messageTransport);
236
+ core.manifest.setPlatform('react-native');
237
+ core.manifest.setRedirectUrl(createURL(''));
238
+ platformChannel.handle('openURL', url => __awaiter(void 0, void 0, void 0, function* () {
239
+ yield openURL(url);
240
+ }));
241
+ platformChannel.handle('openAuthenticationWindow', _a => __awaiter(void 0, [_a], void 0, function* ({
242
+ url,
243
+ redirectUrl
244
+ }) {
245
+ const result = yield openAuthSessionAsync(url, redirectUrl);
246
+ // When not a success, result can only have a type which is a string describing
247
+ // what happened in a single word.
248
+ if (result.type !== 'success') throw new Error(result.type);
249
+ return result.url;
250
+ }));
251
+ };
252
+
253
+ const setupSecureStorageHandler = core => {
254
+ const secureStorageRequestChannel = createRequestChannel(core.messageTransport);
255
+ secureStorageRequestChannel.handle('getSecureItem', getItemAsync);
256
+ secureStorageRequestChannel.handle('setSecureItem', setItemAsync);
257
+ secureStorageRequestChannel.handle('deleteSecureItem', deleteItemAsync);
258
+ };
259
+
260
+ const defaultWebviewUrl = `https://webview.dynamicauth.com/${version}`;
261
+ const ReactNativeExtension = ({
262
+ webviewUrl: _webviewUrl = defaultWebviewUrl,
263
+ webviewDebuggingEnabled,
264
+ appOrigin
265
+ } = {}) => (_, core) => {
266
+ if (appOrigin) core.manifest.setAppOrigin(appOrigin);
267
+ setupPasskeyHandler(core);
268
+ setupFetchHandler(core);
269
+ setupPlatformHandler(core);
270
+ setupSecureStorageHandler(core);
271
+ return {
272
+ reactNative: {
273
+ WebView: createWebView({
274
+ core,
275
+ webviewDebuggingEnabled,
276
+ webviewUrl: _webviewUrl
277
+ })
278
+ }
279
+ };
280
+ };
281
+
282
+ assertPackageVersion('@dynamic-labs/react-native-extension', version);
283
+
284
+ 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.1",
3
+ "version": "4.0.0-alpha.11",
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.1",
19
- "@dynamic-labs/logger": "4.0.0-alpha.1",
20
- "@dynamic-labs/message-transport": "4.0.0-alpha.1"
18
+ "@dynamic-labs/assert-package-version": "4.0.0-alpha.11",
19
+ "@dynamic-labs/client": "4.0.0-alpha.11",
20
+ "@dynamic-labs/logger": "4.0.0-alpha.11",
21
+ "@dynamic-labs/message-transport": "4.0.0-alpha.11"
21
22
  },
22
23
  "peerDependencies": {
23
24
  "react": "^18.2.0",