UNPKG

@oxyhq/services

Version:

OxyHQ Expo/React Native SDK — UI components, screens, and native features

225 lines (212 loc) 8.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = require("react"); var _reactNative = require("react-native"); var _reactNativeGestureHandler = require("react-native-gesture-handler"); var _reactNativeSafeAreaContext = require("react-native-safe-area-context"); var _OxyContext = require("../context/OxyContext.js"); var _reactQuery = require("@tanstack/react-query"); var _FontLoader = require("./FontLoader.js"); var _sonner = require("../../lib/sonner"); var _queryClient = require("../hooks/queryClient.js"); var _storageHelpers = require("../utils/storageHelpers.js"); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } // Initialize fonts automatically (0, _FontLoader.setupFonts)(); // Detect if running on web const isWeb = _reactNative.Platform.OS === 'web'; // Conditionally import components let KeyboardProvider = ({ children }) => children; let BottomSheetRouter = null; let SignInModal = null; // KeyboardProvider only on native if (!isWeb) { try { KeyboardProvider = require('react-native-keyboard-controller').KeyboardProvider; } catch { // KeyboardProvider not available } } // BottomSheetRouter works on all platforms try { BottomSheetRouter = require('./BottomSheetRouter').default; } catch { // BottomSheetRouter not available } // SignInModal works on all platforms try { SignInModal = require('./SignInModal').default; } catch { // SignInModal not available } /** * OxyProvider - Universal provider for Expo apps (native + web) * * Zero-config authentication and session management: * - Native (iOS/Android): Keychain-based identity, bottom sheet auth UI * - Web: FedCM cross-domain SSO, popup fallback * * Usage: * ```tsx * import { OxyProvider, useAuth } from '@oxyhq/services'; * * function App() { * return ( * <OxyProvider baseURL="https://api.oxy.so"> * <YourApp /> * </OxyProvider> * ); * } * * function MyComponent() { * const { isAuthenticated, user, signIn, signOut } = useAuth(); * * if (!isAuthenticated) { * return <OxySignInButton />; * } * return <Text>Welcome, {user?.username}!</Text>; * } * ``` */ const OxyProvider = ({ oxyServices, children, onAuthStateChange, storageKeyPrefix, baseURL, authWebUrl, authRedirectUri, queryClient: providedQueryClient }) => { // Simple storage initialization for query persistence const storageRef = (0, _react.useRef)(null); const queryClientRef = (0, _react.useRef)(null); const [queryClient, setQueryClient] = (0, _react.useState)(null); (0, _react.useEffect)(() => { if (providedQueryClient) { queryClientRef.current = providedQueryClient; setQueryClient(providedQueryClient); return; } // Initialize storage and create query client let mounted = true; (0, _storageHelpers.createPlatformStorage)().then(storage => { if (mounted && !queryClientRef.current) { storageRef.current = storage; const client = (0, _queryClient.createQueryClient)(storage); queryClientRef.current = client; setQueryClient(client); } }).catch(error => { // If storage fails, create query client without persistence if (mounted && !queryClientRef.current) { if (__DEV__) { console.warn('[OxyProvider] Failed to initialize storage for query persistence', error); } const client = (0, _queryClient.createQueryClient)(null); queryClientRef.current = client; setQueryClient(client); } }); return () => { mounted = false; }; }, [providedQueryClient]); // Hook React Query focus manager into app state (native) or visibility (web) (0, _react.useEffect)(() => { if (isWeb) { // Web: use document visibility const handleVisibilityChange = () => { _reactQuery.focusManager.setFocused(document.visibilityState === 'visible'); }; document.addEventListener('visibilitychange', handleVisibilityChange); return () => { document.removeEventListener('visibilitychange', handleVisibilityChange); }; } else { // Native: use AppState const subscription = _reactNative.AppState.addEventListener('change', state => { _reactQuery.focusManager.setFocused(state === 'active'); }); return () => { subscription.remove(); }; } }, []); // Setup network status monitoring for offline detection (0, _react.useEffect)(() => { let cleanup; const setupNetworkMonitoring = async () => { try { if (isWeb) { // Web: use navigator.onLine _reactQuery.onlineManager.setOnline(navigator.onLine); const handleOnline = () => _reactQuery.onlineManager.setOnline(true); const handleOffline = () => _reactQuery.onlineManager.setOnline(false); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); cleanup = () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; } else { // Native: try to use NetInfo try { const NetInfo = await Promise.resolve().then(() => _interopRequireWildcard(require('@react-native-community/netinfo'))); const state = await NetInfo.default.fetch(); _reactQuery.onlineManager.setOnline(state.isConnected ?? true); const unsubscribe = NetInfo.default.addEventListener(state => { _reactQuery.onlineManager.setOnline(state.isConnected ?? true); }); cleanup = () => unsubscribe(); } catch { // NetInfo not available, default to online _reactQuery.onlineManager.setOnline(true); } } } catch (error) { // Default to online if detection fails _reactQuery.onlineManager.setOnline(true); } }; setupNetworkMonitoring(); return () => { cleanup?.(); }; }, []); // Ensure we have a valid QueryClient if (!queryClient) { return null; } // Core content that works on all platforms const coreContent = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactQuery.QueryClientProvider, { client: queryClient, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_OxyContext.OxyContextProvider, { oxyServices: oxyServices, baseURL: baseURL, authWebUrl: authWebUrl, authRedirectUri: authRedirectUri, storageKeyPrefix: storageKeyPrefix, onAuthStateChange: onAuthStateChange, children: [children, BottomSheetRouter && /*#__PURE__*/(0, _jsxRuntime.jsx)(BottomSheetRouter, {}), SignInModal && /*#__PURE__*/(0, _jsxRuntime.jsx)(SignInModal, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sonner.Toaster, {})] }) }); // All platforms use same wrapper (KeyboardProvider is passthrough on web) return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSafeAreaContext.SafeAreaProvider, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureHandlerRootView, { style: { flex: 1 }, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(KeyboardProvider, { children: coreContent }) }) }); }; var _default = exports.default = OxyProvider; //# sourceMappingURL=OxyProvider.js.map