@openfort/react-native 0.0.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 ADDED
@@ -0,0 +1,68 @@
1
+ # Openfort React native SDK
2
+
3
+ ## Install required packages:
4
+
5
+ Using the package manager of your preference, install the openfort-js react native library, e.g. with yarn: `yarn add @openfort/react-native`.
6
+
7
+ Since react native requires installing native dependencies directly, you also have to install these required dependencies
8
+ ```
9
+ yarn add buffer react-native-crypto react-native-get-random-values react-native-randombytes stream-browserify react-native-mmkv
10
+ ```
11
+
12
+ ## Setup your metro config
13
+
14
+ If you do not already have a `metro.config.js`, create one with those required extra node modules:
15
+ ```
16
+ // sample metro.config.js
17
+ const { getDefaultConfig } = require('expo/metro-config');
18
+
19
+ module.exports = (() => {
20
+ const config = getDefaultConfig(__dirname);
21
+
22
+ // Add shims for Node.js modules like crypto and stream
23
+ config.resolver.extraNodeModules = {
24
+ crypto: require.resolve('react-native-crypto'),
25
+ stream: require.resolve('stream-browserify'),
26
+ buffer: require.resolve('buffer'),
27
+ };
28
+
29
+ return config;
30
+ })();
31
+
32
+ ```
33
+ ## Import `Openfort` at the top of your app
34
+ The first file loaded should be Openfort-js polyfills:
35
+ ```
36
+ import "@openfort/react-native/polyfills";
37
+ ```
38
+ This will ensure the correct modules are imported and will ensure `openfort-js` works properly.
39
+
40
+ ## Render secure WebView
41
+
42
+ Openfort uses a `WebView` (from `react-native-webview`) to operate as a secure environment, managing the private key and executing wallet operations. [Learn more](https://www.openfort.xyz/docs/security#embedded-self-custodial-signer).
43
+
44
+ This WebView needs to always be displayed, it is recommended to put it on top of your app. It is wrapped inside a view with `flex: 0`
45
+
46
+ Simply import it from `@openfort/react-native`
47
+
48
+ ```
49
+ // Sample app/_layout.tsx using expo router
50
+ import { OpenfortCommunicationWebView } from '@openfort/react-native';
51
+
52
+ export default function RootLayout() {
53
+
54
+ return (
55
+ <>
56
+ <OpenfortCommunicationWebView />
57
+ <Slot />
58
+ </>
59
+ );
60
+ }
61
+ ```
62
+ ## Notes
63
+
64
+ Because we are using `mmkv` storage, expo-go will not work. To run your app use `expo run:ios` or `expo run:android`.
65
+
66
+ # Sample
67
+
68
+ You can check out the [React native auth sample](https://github.com/openfort-xyz/react-native-auth-sample) to get your app running.
package/dist/Iframe.js ADDED
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { View } from "react-native";
4
+ import WebView from "react-native-webview";
5
+ const injectedCode = `
6
+ window.parent = {};
7
+ window.parent.postMessage = (msg) => window.ReactNativeWebView.postMessage(JSON.stringify(msg))
8
+ `;
9
+ export default function Iframe({ customUri }) {
10
+ const webViewRef = useRef(null);
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ const fnCallbackRef = useRef(null); // Ref to store the callback
13
+ const [loaded, setLoaded] = useState(false);
14
+ useEffect(() => {
15
+ global.openfortListener = (fn) => {
16
+ fnCallbackRef.current = fn; // Store the callback in the ref
17
+ };
18
+ global.openfortPostMessage = (message) => {
19
+ webViewRef?.current?.postMessage(JSON.stringify(message));
20
+ setLoaded(true);
21
+ };
22
+ }, [webViewRef?.current]);
23
+ const handleMessage = (event) => {
24
+ // Trigger the stored callback, if any
25
+ if (fnCallbackRef.current) {
26
+ const origin = event.nativeEvent.url.endsWith('/') ? event.nativeEvent.url.slice(0, -1) : event.nativeEvent.url;
27
+ fnCallbackRef.current({ origin, data: event.nativeEvent.data });
28
+ }
29
+ };
30
+ if (!loaded)
31
+ return null;
32
+ const uri = customUri ? customUri : "https://embedded.openfort.xyz";
33
+ return (React.createElement(View, { style: { flex: 0 } },
34
+ React.createElement(WebView, { ref: webViewRef, source: { uri: uri }, onMessage: handleMessage, injectedJavaScript: injectedCode })));
35
+ }
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { default as Iframe } from './Iframe';
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export default function Iframe({ customUri }: {
3
+ customUri?: string;
4
+ }): React.JSX.Element | null;
@@ -0,0 +1 @@
1
+ export { default as Iframe } from './Iframe';
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@openfort/react-native",
3
+ "main": "dist/index.js",
4
+ "version": "0.0.1",
5
+ "scripts": {
6
+ "build": "rimraf dist && tsc",
7
+ "lint": "eslint . --ignore-pattern dist"
8
+ },
9
+ "types": "dist/types/index.d.ts",
10
+ "files": [
11
+ "dist",
12
+ "polyfills"
13
+ ],
14
+ "dependencies": {
15
+ "events": "^3.3.0",
16
+ "react-native-get-random-values": "^1.11.0",
17
+ "react-native-mmkv": "^3.2.0",
18
+ "react-native-randombytes": "^3.6.1",
19
+ "react-native-webview": "13.12.5",
20
+ "text-encoding": "^0.7.0"
21
+ },
22
+ "peerDependencies": {
23
+ "@openfort/openfort-js": "^0.8.15",
24
+ "react": "*",
25
+ "react-native": "*"
26
+ },
27
+ "devDependencies": {
28
+ "@openfort/openfort-js": "^0.8.15",
29
+ "react": "18.3.1",
30
+ "react-native": "0.76.5",
31
+ "@eslint/js": "^9.17.0",
32
+ "@types/react": "~18.3.12",
33
+ "@types/react-test-renderer": "^18.3.0",
34
+ "eslint": "^9.17.0",
35
+ "eslint-plugin-react": "^7.37.3",
36
+ "globals": "^15.14.0",
37
+ "typescript": "^5.3.3",
38
+ "typescript-eslint": "^8.19.0"
39
+ },
40
+ "private": false,
41
+ "packageManager": "yarn@1.22.17"
42
+ }
@@ -0,0 +1,78 @@
1
+ import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions"
2
+
3
+ // This is a workaround to fix the issue with process.version
4
+ if (process.version === undefined) {
5
+ Object.defineProperty(process, 'version', {
6
+ value: "", // Set the desired version (you can use any string)
7
+ writable: false,
8
+ });
9
+ }
10
+
11
+ // Crypto module needs getRandomValues
12
+ import 'react-native-get-random-values';
13
+
14
+ const MMKVStorage = require("react-native-mmkv").MMKV;
15
+
16
+ // Initialize MMKVStorage
17
+ const MMKV = new MMKVStorage();
18
+
19
+ const localStorage: Storage = {
20
+ getItem: (key: string): string | null => {
21
+ try {
22
+ const value = MMKV.getString(key);
23
+ // console.log("getItem", key, value);
24
+ return value !== undefined ? value : null; // Ensure it returns string or null
25
+ } catch (e) {
26
+ console.error('Error reading value from localStorage polyfill', e);
27
+ return null;
28
+ }
29
+ },
30
+ setItem: (key: string, value: string) => {
31
+ try {
32
+ // console.log("setItem", key, value);
33
+ MMKV.set(key, value); // Sets value synchronously
34
+ } catch (e) {
35
+ console.error('Error saving value to localStorage polyfill', e);
36
+ }
37
+ },
38
+ removeItem: (key: string) => {
39
+ try {
40
+ // console.log("removeItem", key);
41
+ MMKV.delete(key); // Removes item synchronously
42
+ } catch (e) {
43
+ console.error('Error removing value from localStorage polyfill', e);
44
+ }
45
+ },
46
+ clear: () => {
47
+ try {
48
+ // console.log("clear");
49
+ MMKV.clearAll(); // Clears store synchronously
50
+ } catch (e) {
51
+ console.error('Error clearing localStorage polyfill', e);
52
+ }
53
+ },
54
+ key: (index: number): string | null => {
55
+ return MMKV.getAllKeys()[index] || null;
56
+ },
57
+ get length(): number {
58
+ try {
59
+ return MMKV.getAllKeys().length;
60
+ } catch {
61
+ console.error('Error: localStorage.length is not supported');
62
+ return -1;
63
+ }
64
+ }
65
+ };
66
+
67
+ global.localStorage = localStorage;
68
+ global.sessionStorage = localStorage;
69
+
70
+ // for TextEncoder and TextDecoder
71
+ const applyGlobalPolyfills = () => {
72
+ const { TextEncoder, TextDecoder } = require("text-encoding")
73
+
74
+ polyfillGlobal("TextEncoder", () => TextEncoder)
75
+ polyfillGlobal("TextDecoder", () => TextDecoder)
76
+ }
77
+
78
+ applyGlobalPolyfills()