diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 000000000..79860b3a9 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,5 @@ +// Folder-specific settings +// +// For a full list of overridable settings, and general information on folder-specific settings, +// see the documentation: https://zed.dev/docs/configuring-zed#settings-files +{} diff --git a/dashboard/pnpm-lock.yaml b/dashboard/pnpm-lock.yaml index bf530158d..dcf6fa4c2 100644 --- a/dashboard/pnpm-lock.yaml +++ b/dashboard/pnpm-lock.yaml @@ -9,7 +9,7 @@ overrides: js-yaml@<=4.1.0: '>=4.1.1' glob@>=10.3.7 <=11.0.3: '>=11.1.0' -packageExtensionsChecksum: sha256-gRFeykwiwMfEE6etcYx6N48XwVeKzxbqNveL7KTQgSQ= +packageExtensionsChecksum: 60d08afe00baf23dd9656c15a43f9c54 importers: diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml index 40d377e74..0d6afaf8c 100644 --- a/docs/pnpm-lock.yaml +++ b/docs/pnpm-lock.yaml @@ -8,7 +8,7 @@ overrides: js-yaml@<=4.1.0: '>=4.1.1' glob@>=10.3.7 <=11.0.3: '>=11.1.0' -packageExtensionsChecksum: sha256-4+NJJHoeDEOtWI2UxgTNLimXyrOojBs00S85/9Babm0= +packageExtensionsChecksum: ff1808c55b54aac157f52213f5265af9 importers: diff --git a/examples/demos/Makefile b/examples/demos/Makefile deleted file mode 100644 index 78a50a417..000000000 --- a/examples/demos/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -ROOT_DIR?=$(abspath ../..) -include $(ROOT_DIR)/build/makefiles/general.makefile - - -.PHONY: _dev-env-up -_dev-env-up: - @echo "Nothing to do" - - -.PHONY: _dev-env-down -_dev-env-down: - @echo "Nothing to do" - - -.PHONY: _dev-env-build -_dev-env-build: - @echo "Nothing to do" diff --git a/examples/demos/ReactNativeDemo/.gitignore b/examples/demos/ReactNativeDemo/.gitignore deleted file mode 100644 index f610ec0d6..000000000 --- a/examples/demos/ReactNativeDemo/.gitignore +++ /dev/null @@ -1,39 +0,0 @@ -# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files - -# dependencies -node_modules/ - -# Expo -.expo/ -dist/ -web-build/ -expo-env.d.ts - -# Native -.kotlin/ -*.orig.* -*.jks -*.p8 -*.p12 -*.key -*.mobileprovision - -# Metro -.metro-health-check* - -# debug -npm-debug.* -yarn-debug.* -yarn-error.* - -# macOS -.DS_Store -*.pem - -# local env files -.env*.local - -# typescript -*.tsbuildinfo - -app-example diff --git a/examples/demos/ReactNativeDemo/APPLE_SIGN_IN_SETUP.md b/examples/demos/ReactNativeDemo/APPLE_SIGN_IN_SETUP.md deleted file mode 100644 index 683d271a3..000000000 --- a/examples/demos/ReactNativeDemo/APPLE_SIGN_IN_SETUP.md +++ /dev/null @@ -1,95 +0,0 @@ -# Setting Up Apple Sign In for Nhost Authentication - -This guide will walk you through the steps to configure Apple Sign In for your React Native application with Nhost authentication. - -## Prerequisites - -- An Apple Developer account -- Xcode 11 or later -- Access to the Apple Developer portal - -## 1. Configure Your App in the Apple Developer Portal - -1. Log in to the [Apple Developer portal](https://developer.apple.com/) -2. Go to "Certificates, Identifiers & Profiles" -3. Select "Identifiers" and create a new App ID if you haven't already -4. Enable "Sign In with Apple" capability for your App ID -5. Save your changes - -## 2. Create a Service ID for Sign In with Apple - -1. In the Apple Developer portal, go to "Certificates, Identifiers & Profiles" -2. Select "Identifiers" and click the "+" button to add a new identifier -3. Choose "Services IDs" and click "Continue" -4. Enter a description and identifier (e.g., "com.nhost.reactnativewebdemo.service") -5. Check "Sign In with Apple" and click "Configure" -6. Add your domain to the "Domains and Subdomains" field -7. Add your return URL in the "Return URLs" field. This should match your Nhost redirect URL -8. Save and register the service ID - -## 3. Configure Nhost for Apple Sign In - -1. In your Nhost dashboard, go to Authentication > Providers > Apple -2. Enable the provider -3. Enter the following details: - - Team ID: Found in your Apple Developer account - - Service ID: The identifier you created in step 2 - - Key ID: Create a new key with "Sign In with Apple" enabled in the Apple Developer portal - - Private Key: The downloaded key file content - -## 4. Configure Your Expo/React Native App - -1. Make sure the `expo-apple-authentication` package is installed - - ``` - npx expo install expo-apple-authentication - ``` - -2. Ensure your app.json has the proper configuration: - - ```json - { - "expo": { - "ios": { - "bundleIdentifier": "com.nhost.reactnativewebdemo", - "infoPlist": { - "NSFaceIDUsageDescription": "This app uses Face ID for signing in" - } - }, - "plugins": ["expo-apple-authentication"] - } - } - ``` - -3. If you're using EAS Build, make sure you've configured your Apple Developer Team ID: - ``` - eas credentials - ``` - -## 5. Testing Apple Sign In - -When you build your app for iOS: - -1. Use a real device or simulator running iOS 13 or later -2. Make sure you're signed into an Apple ID on the device -3. Use the Apple Sign In button and authenticate -4. The app will receive an ID token that is sent to Nhost -5. Nhost will verify the token and create or authenticate the user - -## Troubleshooting - -- **Invalid Client ID**: Ensure your Service ID is properly configured in the Apple Developer portal -- **Authentication Failed**: Check that your Nhost Apple provider configuration is correct -- **App Build Issues**: Ensure the `expo-apple-authentication` package is properly installed and your app.json is configured correctly - -## Security Considerations - -- Never store Apple private keys in your front-end code -- The authentication process should always validate tokens on the server side (which Nhost handles) -- Keep your Apple Developer account secure - -## Additional Resources - -- [Apple Sign In Documentation](https://developer.apple.com/sign-in-with-apple/) -- [Nhost Authentication Documentation](https://docs.nhost.io/authentication) -- [Expo Apple Authentication Documentation](https://docs.expo.dev/versions/latest/sdk/apple-authentication/) diff --git a/examples/demos/ReactNativeDemo/README.md b/examples/demos/ReactNativeDemo/README.md deleted file mode 100644 index 624ca4707..000000000 --- a/examples/demos/ReactNativeDemo/README.md +++ /dev/null @@ -1,169 +0,0 @@ -# Nhost SDK Demo - React Native - -This is a comprehensive React Native demo showcasing the Nhost SDK integration with Expo. The application demonstrates various authentication methods, user management, file operations, and GraphQL interactions in a modern React Native environment. - -## Features - -- **Email/Password Authentication** - Traditional sign-up and sign-in with email -- **Multi-Factor Authentication (MFA)** - TOTP-based 2FA security -- **Magic Link Authentication** - Passwordless authentication via email -- **Social Authentication** - GitHub OAuth integration -- **Native Authentication** - Apple Sign-In for iOS devices -- **User Profile Management** - Display and manage user information -- **Protected Routes** - Route-based authentication guards -- **Session Persistence** - Reliable session storage with AsyncStorage -- **File Operations** - Upload and download functionality -- **GraphQL Operations** - Database queries and mutations - -## Quick Start - -1. **Install dependencies** - - ```bash - pnpm install - ``` - -2. **Configure Nhost** - - Update `app.json` with your Nhost configuration: - - ```json - "extra": { - "NHOST_SUBDOMAIN": "your-subdomain", - "NHOST_REGION": "your-region" - } - ``` - - For local development with Nhost CLI: - - ```json - "extra": { - "NHOST_SUBDOMAIN": "192-168-1-103", - "NHOST_REGION": "local" - } - ``` - - _(Replace with your actual local IP address using hyphens instead of dots)_ - -3. **Start the development server** - - ```bash - pnpm start - ``` - -4. **Open the app** - - Scan QR code with Expo Go - - Press `i` for iOS Simulator - - Press `a` for Android Emulator - -## Project Structure - -The project uses [Expo Router](https://docs.expo.dev/router/introduction/) for file-based navigation: - -``` -ReactNativeWebDemo/ -├── app/ -│ ├── _layout.tsx # Root layout with AuthProvider -│ ├── index.tsx # Home/landing screen -│ ├── signin.tsx # Authentication hub with tabs -│ ├── signup.tsx # User registration -│ ├── profile.tsx # Protected user profile -│ ├── upload.tsx # File upload demo -│ ├── verify.tsx # Magic link/social auth verification -│ │ -│ ├── components/ -│ │ ├── ProtectedScreen.tsx # Route protection wrapper -│ │ ├── MagicLinkForm.tsx # Magic link authentication -│ │ ├── SocialLoginForm.tsx # GitHub OAuth -│ │ ├── NativeLoginForm.tsx # Native auth container -│ │ ├── AppleSignIn.tsx # Apple Sign-In (iOS) -│ │ └── MFASettings.tsx # Multi-factor authentication -│ │ -│ └── lib/ -│ ├── nhost/ -│ │ ├── AuthProvider.tsx # Authentication context -│ │ └── AsyncStorage.tsx # Session persistence adapter -│ └── utils.ts # Utility functions -│ -├── assets/ # App icons and images -├── app.json # Expo configuration -└── README files # Documentation (this file and others) -``` - -## Architecture Overview - -### Authentication Flow - -1. **AuthProvider** wraps the entire app providing global auth state -2. **ProtectedScreen** component guards routes requiring authentication -3. **Session persistence** maintains login state across app restarts -4. **Deep linking** handles magic links and OAuth redirects - -### Key Components - -- **AuthProvider**: Central authentication state management -- **ProtectedScreen**: Higher-order component for route protection -- **Verification flows**: Unified handling for magic links and OAuth callbacks -- **Storage adapter**: Custom AsyncStorage implementation for session persistence - -### Supported Authentication Methods - -1. **Email/Password**: Traditional username/password with MFA support -2. **Magic Links**: Passwordless authentication via email verification -3. **Social OAuth**: GitHub integration with redirect handling -4. **Native Authentication**: Apple Sign-In using secure enclave - -## Configuration - -### Environment Variables - -Set these values in `app.json` under the `extra` section: - -| Variable | Description | Example | -| ----------------- | ---------------------------- | ------------- | -| `NHOST_SUBDOMAIN` | Your Nhost project subdomain | `"myproject"` | -| `NHOST_REGION` | Nhost region | `"us-east-1"` | - -### Deep Linking Setup - -The app is configured with the scheme `reactnativewebdemo://` for standalone builds and uses Expo's linking system for development. - -## Development - -### Local Nhost Backend - -To run against a local Nhost backend: - -1. Start Nhost CLI: - - ```bash - nhost dev - ``` - -2. Update `app.json`: - ```json - "extra": { - "NHOST_REGION": "local", - "NHOST_SUBDOMAIN": "local" - } - ``` - -### Testing Authentication - -- Use the sign-in screen's tabbed interface to test different auth methods -- Magic links work in development through proper deep link configuration -- Social authentication requires OAuth app setup in your Nhost dashboard - -## Documentation - -- [Protected Routes & Email Auth](./README_PROTECTED_ROUTES.md) -- [Native Authentication](./README_NATIVE_AUTHENTICATION.md) -- [Magic Links](./README_MAGIC_LINKS.md) -- [Social Sign-In](./README_SOCIAL_SIGNIN.md) - -## Learn More - -- [Nhost Documentation](https://docs.nhost.io/) -- [Expo Router Documentation](https://docs.expo.dev/router/) -- [React Native Documentation](https://reactnative.dev/) -- [Expo Documentation](https://docs.expo.dev/) diff --git a/examples/demos/ReactNativeDemo/README_MAGIC_LINKS.md b/examples/demos/ReactNativeDemo/README_MAGIC_LINKS.md deleted file mode 100644 index abc3d1fc5..000000000 --- a/examples/demos/ReactNativeDemo/README_MAGIC_LINKS.md +++ /dev/null @@ -1,410 +0,0 @@ -# Magic Links Authentication - -This document explains how magic links (passwordless authentication) are implemented in the Nhost React Native demo, including deep linking configuration, verification endpoints, and testing strategies. - -## Overview - -Magic links provide a passwordless authentication method where users receive an email containing a link that automatically authenticates them when clicked. This implementation handles both Expo Go development and standalone app scenarios. - -## How Magic Links Work - -### Authentication Flow - -1. **Email Collection**: User enters their email address -2. **Link Generation**: App requests magic link from Nhost with appropriate redirect URL -3. **Email Delivery**: Nhost sends email with authentication link -4. **Link Click**: User clicks link, which opens the app via deep linking -5. **Token Extraction**: App extracts refresh token from the URL parameters -6. **Authentication**: App uses refresh token to authenticate with Nhost -7. **Redirect**: User is redirected to their profile upon successful authentication - -## Implementation Details - -### MagicLinkForm Component - -```typescript -// app/components/MagicLinkForm.tsx -export default function MagicLinkForm() { - const [email, setEmail] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [success, setSuccess] = useState(false); - const { nhost } = useAuth(); - - const handleSubmit = async () => { - setIsLoading(true); - setError(null); - - try { - // Create the correct redirect URL for current environment - const redirectUrl = Linking.createURL("verify"); - - await nhost.auth.signInPasswordlessEmail({ - email, - options: { - redirectTo: redirectUrl, - }, - }); - - setSuccess(true); - } catch (err) { - const error = err as FetchError; - setError( - `An error occurred while sending the magic link: ${error.message}`, - ); - } finally { - setIsLoading(false); - } - }; - - // ... UI implementation -} -``` - -### Key Features - -1. **Environment Detection**: Automatically generates correct redirect URLs for Expo Go vs standalone -2. **Error Handling**: Comprehensive error handling with user-friendly messages -3. **Loading States**: Visual feedback during magic link generation -4. **Success Feedback**: Confirmation when magic link is sent - -## Deep Linking Configuration - -### App Configuration - -The app supports deep linking through custom URL schemes: - -```json -// app.json -{ - "expo": { - "scheme": "reactnativewebdemo", - "ios": { - "infoPlist": { - "CFBundleURLTypes": [ - { - "CFBundleURLSchemes": ["reactnativewebdemo"] - } - ] - } - } - } -} -``` - -### URL Format Differences - -#### Standalone App - -``` -reactnativewebdemo://verify?refreshToken=abc123... -``` - -#### Expo Go Development - -``` -exp://192.168.1.103:19000/--/verify?refreshToken=abc123... -``` - -### Dynamic URL Generation - -```typescript -// Automatically creates correct URL format for current environment -const redirectUrl = Linking.createURL("verify"); - -// In Expo Go: exp://192.168.1.103:19000/--/verify -// In standalone: reactnativewebdemo://verify -``` - -## Verification Endpoint - -### Verify Screen Implementation - -```typescript -// app/verify.tsx -export default function Verify() { - const params = useLocalSearchParams<{ refreshToken: string }>(); - const [status, setStatus] = useState<"verifying" | "success" | "error">( - "verifying", - ); - const { nhost, isAuthenticated } = useAuth(); - - useEffect(() => { - const refreshToken = params.refreshToken; - - if (!refreshToken) { - setStatus("error"); - setError("No refresh token found in the link"); - return; - } - - async function processToken(): Promise { - try { - // Brief delay to show verifying state - await new Promise((resolve) => setTimeout(resolve, 500)); - - // Authenticate using the refresh token - await nhost.auth.refreshToken({ refreshToken }); - - setStatus("success"); - - // Redirect to profile after brief success message - setTimeout(() => { - router.replace("/profile"); - }, 1500); - } catch (err) { - setStatus("error"); - setError(`Authentication failed: ${err.message}`); - } - } - - processToken(); - }, [params, nhost.auth]); - - // ... UI implementation for different states -} -``` - -### Verification States - -1. **Verifying**: Shows loading spinner while processing token -2. **Success**: Displays success message before redirect -3. **Error**: Shows error details and debugging information - -## URL Parameter Handling - -### Token Extraction - -The verify screen extracts authentication parameters from the URL: - -```typescript -// Extract refresh token from URL parameters -const params = useLocalSearchParams<{ refreshToken: string }>(); -const refreshToken = params.refreshToken; - -// Validate token presence -if (!refreshToken) { - setStatus("error"); - setError("No refresh token found in the link"); - return; -} -``` - -### Debug Information - -For development, the verify screen can display all received parameters: - -```typescript -// Debug: Show all URL parameters (development only) -if (__DEV__) { - const allParams: Record = {}; - Object.entries(params).forEach(([key, value]) => { - if (typeof value === "string") { - allParams[key] = value; - } - }); - console.log("Received URL parameters:", allParams); -} -``` - -## Testing Magic Links - -### Development with Expo Go - -1. **Start Development Server**: - - ```bash - npx expo start - ``` - -2. **Note Your Local URL**: - - - Check terminal output for development URL (e.g., `exp://192.168.1.103:19000`) - -3. **Send Magic Link**: - - - Use Magic Link form in the app - - Enter your email address - - Submit the form - -4. **Check Email Format**: - - - Magic link should use format: `exp://192.168.1.103:19000/--/verify?refreshToken=...` - - The `--` segment is crucial for Expo Go routing - -5. **Test the Link**: - - Open email on device with Expo Go installed - - Tap the magic link - - Should open directly in Expo Go - -### Testing Strategies - -#### Manual Testing - -```typescript -// Test different scenarios -const testScenarios = [ - "Valid magic link with correct token", - "Expired magic link", - "Invalid refresh token", - "Malformed URL parameters", - "Network connectivity issues", - "Already authenticated user", -]; -``` - -#### Automated URL Testing - -```typescript -// Manually test URL handling -const testUrls = [ - "exp://192.168.1.103:19000/--/verify?refreshToken=valid_token", - "exp://192.168.1.103:19000/--/verify?refreshToken=invalid_token", - "exp://192.168.1.103:19000/--/verify", // Missing token -]; -``` - -## Environment-Specific Considerations - -### Expo Go Limitations - -1. **URL Format**: Must use `exp://` protocol with development server URL -2. **Port Changes**: URL changes if development server restarts on different port -3. **Network Dependency**: Requires same network for device and development machine -4. **Debug Access**: Can inspect URL parameters more easily - -### Standalone App Benefits - -1. **Custom Scheme**: Uses app's custom URL scheme (`reactnativewebdemo://`) -2. **Universal Links**: Can configure universal links for production -3. **App Store Distribution**: Works with published apps -4. **Offline Capability**: Less dependent on development server - -## Security Considerations - -### Token Security - -1. **Short-Lived Tokens**: Refresh tokens have limited lifespan -2. **Single Use**: Tokens are invalidated after successful authentication -3. **Secure Transport**: Links are sent via secure email delivery -4. **Validation**: Server-side token validation prevents tampering - -### Best Practices - -```typescript -// Implement proper error handling -const processToken = async (token: string) => { - try { - // Validate token format before sending to server - if (!token || token.length < 10) { - throw new Error("Invalid token format"); - } - - // Use the token - await nhost.auth.refreshToken({ refreshToken: token }); - } catch (error) { - // Log error for debugging but don't expose details to user - console.error("Magic link authentication failed:", error); - throw new Error("Authentication failed. Please try again."); - } -}; -``` - -## Troubleshooting - -### Common Issues - -| Issue | Symptom | Solution | -| ---------------------------------- | --------------------------------------- | ------------------------------------------------------------- | -| Link doesn't open app | Clicking link opens browser instead | Check URL scheme configuration and Expo Go installation | -| "No refresh token" error | Link opens app but shows error | Verify email contains correct URL format with parameters | -| Network errors during verification | Authentication fails with network error | Check Nhost configuration and internet connectivity | -| Wrong URL format in email | Link uses incorrect protocol or format | Verify `Linking.createURL()` usage and development server URL | - -### Debug Steps - -1. **Check Console Logs**: - - ```typescript - console.log("Generated redirect URL:", redirectUrl); - console.log("Received URL parameters:", params); - ``` - -2. **Verify Email Content**: - - - Check that email contains correct URL format - - Ensure refresh token parameter is present - -3. **Test URL Manually**: - - - Copy magic link from email - - Paste into browser or use device's URL handler - -4. **Network Debugging**: - - Ensure device and development machine are on same network - - Check firewall settings - -### Expo Go Specific Debugging - -```typescript -// Debug Expo Go URLs -if (__DEV__) { - const expoUrl = Linking.createURL("verify"); - console.log("Expo Go URL format:", expoUrl); - - // Should output something like: - // exp://192.168.1.103:19000/--/verify -} -``` - -## Production Deployment - -### Universal Links (iOS) - -For production iOS apps, configure universal links: - -```json -// apple-app-site-association -{ - "applinks": { - "apps": [], - "details": [ - { - "appID": "TEAMID.com.nhost.reactnativewebdemo", - "paths": ["/verify*"] - } - ] - } -} -``` - -### App Links (Android) - -Configure Android app links for seamless user experience: - -```xml - - - - - - - - - -``` - -## Related Documentation - -- [Protected Routes & Email Auth](./README_PROTECTED_ROUTES.md) -- [Native Authentication](./README_NATIVE_AUTHENTICATION.md) -- [Social Sign-In](./README_SOCIAL_SIGNIN.md) - -## External Resources - -- [Expo Linking Documentation](https://docs.expo.dev/guides/linking/) -- [React Navigation Deep Linking](https://reactnavigation.org/docs/deep-linking/) -- [Nhost Passwordless Authentication](https://docs.nhost.io/authentication/passwordless) -- [Universal Links (iOS)](https://developer.apple.com/ios/universal-links/) -- [Android App Links](https://developer.android.com/training/app-links) diff --git a/examples/demos/ReactNativeDemo/README_NATIVE_AUTHENTICATION.md b/examples/demos/ReactNativeDemo/README_NATIVE_AUTHENTICATION.md deleted file mode 100644 index fcef3a654..000000000 --- a/examples/demos/ReactNativeDemo/README_NATIVE_AUTHENTICATION.md +++ /dev/null @@ -1,381 +0,0 @@ -# Native Authentication - Apple Sign-In - -This document explains how native authentication with Apple Sign-In is implemented in the Nhost React Native demo, including deep linking, nonce generation, ID tokens, and security considerations. - -## Overview - -Apple Sign-In provides a secure, privacy-focused authentication method for iOS users. The implementation uses cryptographic nonces, identity tokens, and deep linking to ensure a secure authentication flow between the app, Apple's servers, and Nhost. - -## Architecture - -### Authentication Flow - -1. **Nonce Generation**: Create a cryptographic nonce for request verification -2. **Apple Authentication**: Request user authentication from Apple -3. **Identity Token**: Receive signed JWT from Apple containing user information -4. **Nhost Verification**: Send identity token and nonce to Nhost for verification -5. **Session Creation**: Nhost validates the token and creates a user session - -## Implementation Details - -### Apple Sign-In Component - -```typescript -// app/components/AppleSignIn.tsx -const AppleSignIn: React.FC = ({ setIsLoading }) => { - const { nhost } = useAuth(); - const [appleAuthAvailable, setAppleAuthAvailable] = useState(false); - - // Check Apple authentication availability - useEffect(() => { - const checkAvailability = async () => { - if (Platform.OS === "ios") { - const isAvailable = await AppleAuthentication.isAvailableAsync(); - setAppleAuthAvailable(isAvailable); - } - }; - checkAvailability(); - }, []); - - const handleAppleSignIn = async () => { - try { - // Generate cryptographic nonce - const nonce = Math.random().toString(36).substring(2, 15); - const hashedNonce = await Crypto.digestStringAsync( - Crypto.CryptoDigestAlgorithm.SHA256, - nonce, - ); - - // Request Apple authentication - const credential = await AppleAuthentication.signInAsync({ - requestedScopes: [ - AppleAuthentication.AppleAuthenticationScope.FULL_NAME, - AppleAuthentication.AppleAuthenticationScope.EMAIL, - ], - nonce: hashedNonce, - }); - - // Authenticate with Nhost - if (credential.identityToken) { - const response = await nhost.auth.signInIdToken({ - provider: "apple", - idToken: credential.identityToken, - nonce, // Original unhashed nonce - }); - - if (response.body?.session) { - router.replace("/profile"); - } - } - } catch (error) { - // Handle authentication errors - } - }; -}; -``` - -## Security Mechanisms - -### Cryptographic Nonce - -The nonce prevents replay attacks and ensures request authenticity: - -```typescript -// Generate random nonce -const nonce = Math.random().toString(36).substring(2, 15); - -// Hash nonce for Apple (SHA256) -const hashedNonce = await Crypto.digestStringAsync( - Crypto.CryptoDigestAlgorithm.SHA256, - nonce, -); - -// Send hashed nonce to Apple -const credential = await AppleAuthentication.signInAsync({ - nonce: hashedNonce, - // ... -}); - -// Send original nonce to Nhost for verification -await nhost.auth.signInIdToken({ - provider: "apple", - idToken: credential.identityToken, - nonce, // Original unhashed nonce -}); -``` - -### Why Nonce is Important - -1. **Replay Attack Prevention**: Ensures each authentication request is unique -2. **Request Binding**: Links the Apple response to the specific app request -3. **Tampering Detection**: Detects if the response has been modified -4. **Time-bound Security**: Nonces typically have short lifespans - -### Identity Token Structure - -Apple returns a JWT (JSON Web Token) containing: - -```json -{ - "iss": "https://appleid.apple.com", - "aud": "com.nhost.reactnativewebdemo", - "exp": 1634567890, - "iat": 1634564290, - "sub": "000123.abc456def789...", - "nonce": "hashed_nonce_value", - "email": "user@example.com", - "email_verified": "true", - "real_user_indicator": "true" -} -``` - -## Platform Requirements - -### iOS Configuration - -The app must be properly configured for Apple Sign-In: - -```json -// app.json -{ - "expo": { - "ios": { - "bundleIdentifier": "com.nhost.reactnativewebdemo", - "infoPlist": { - "NSFaceIDUsageDescription": "This app uses Face ID for signing in" - } - }, - "plugins": ["expo-apple-authentication"] - } -} -``` - -### Availability Check - -Apple Sign-In is only available on iOS 13+ devices: - -```typescript -const checkAvailability = async () => { - if (Platform.OS === "ios") { - const isAvailable = await AppleAuthentication.isAvailableAsync(); - setAppleAuthAvailable(isAvailable); - } -}; -``` - -## Nhost Configuration - -### Apple Provider Setup - -Configure Apple as an authentication provider in your Nhost dashboard: - -1. **Team ID**: Your Apple Developer Team ID -2. **Service ID**: Apple Services ID for your app -3. **Key ID**: Apple Sign-In key identifier -4. **Private Key**: Apple Sign-In private key (P8 file content) - -### Server-Side Verification - -Nhost performs server-side verification of the identity token: - -1. **Signature Verification**: Validates JWT signature using Apple's public keys -2. **Nonce Verification**: Compares hashed nonce in token with provided nonce -3. **Audience Verification**: Ensures token is intended for your app -4. **Expiration Check**: Validates token hasn't expired -5. **Issuer Validation**: Confirms token comes from Apple - -## Deep Linking Integration - -### URL Scheme Configuration - -The app is configured with custom URL schemes for deep linking: - -```json -// app.json -{ - "expo": { - "scheme": "reactnativewebdemo", - "ios": { - "infoPlist": { - "CFBundleURLTypes": [ - { - "CFBundleURLSchemes": ["reactnativewebdemo"] - } - ] - } - } - } -} -``` - -### Handling Deep Links - -While Apple Sign-In typically doesn't require custom deep linking (it's handled within the app), the configuration supports it for other authentication flows: - -```typescript -// app/verify.tsx - Used by other auth methods -useEffect(() => { - const subscription = Linking.addEventListener("url", handleDeepLink); - return () => subscription?.remove(); -}, []); - -const handleDeepLink = (event: { url: string }) => { - // Handle incoming deep links from authentication providers -}; -``` - -## Error Handling - -### Common Apple Sign-In Errors - -```typescript -const handleAppleSignIn = async () => { - try { - // ... authentication logic - } catch (error: any) { - if (error.code === "ERR_CANCELED") { - // User canceled authentication - return; - } - - if (error.code === "ERR_INVALID_RESPONSE") { - Alert.alert("Error", "Invalid response from Apple"); - return; - } - - if (error.code === "ERR_NOT_AVAILABLE") { - Alert.alert("Error", "Apple Sign-In not available on this device"); - return; - } - - // Generic error handling - Alert.alert("Authentication Error", error.message || "Unknown error"); - } -}; -``` - -### Nhost Integration Errors - -```typescript -const response = await nhost.auth.signInIdToken({ - provider: "apple", - idToken: credential.identityToken, - nonce, -}); - -if (response.error) { - switch (response.error.message) { - case "Invalid identity token": - Alert.alert("Error", "Authentication failed. Please try again."); - break; - case "Invalid nonce": - Alert.alert("Error", "Security verification failed"); - break; - default: - Alert.alert("Error", "Authentication error occurred"); - } -} -``` - -## Privacy Features - -### Apple's Privacy Protection - -Apple Sign-In provides enhanced privacy features: - -1. **Email Relay**: Apple can provide relay emails to protect user's real email -2. **Minimal Data**: Only requests necessary user information -3. **User Control**: Users can choose what information to share -4. **Private Email**: Option to hide real email address - -### Handling Private Emails - -```typescript -// Handle Apple's private relay emails -const credential = await AppleAuthentication.signInAsync({ - requestedScopes: [ - AppleAuthentication.AppleAuthenticationScope.EMAIL, - AppleAuthentication.AppleAuthenticationScope.FULL_NAME, - ], - nonce: hashedNonce, -}); - -// Email might be a private relay address -console.log("Email:", credential.email); // Could be privaterelay@example.com -``` - -## Testing - -### Development Testing - -1. **iOS Simulator**: Apple Sign-In works in iOS Simulator (iOS 14+) -2. **Physical Device**: Test on real iOS devices for complete functionality -3. **Xcode Console**: Monitor authentication flow through Xcode logs - -### Test Scenarios - -```typescript -// Test different authentication states -const testScenarios = [ - "First-time sign in with Apple ID", - "Returning user authentication", - "User cancels authentication", - "Network connection issues", - "Invalid Apple ID credentials", - "Apple ID with 2FA enabled", -]; -``` - -## Security Best Practices - -### Implementation Guidelines - -1. **Always Use Nonce**: Never skip nonce generation for production apps -2. **Validate Server-Side**: Let Nhost handle token validation -3. **Handle Errors Gracefully**: Provide clear feedback to users -4. **Secure Storage**: Let Nhost handle session storage securely -5. **Regular Updates**: Keep Apple authentication libraries updated - -### Production Considerations - -1. **Apple Developer Account**: Requires paid Apple Developer membership -2. **App Store Review**: Apple Sign-In must be implemented if other social logins exist -3. **Bundle ID Matching**: Ensure bundle ID matches Apple configuration -4. **Certificate Management**: Keep Apple certificates and keys updated - -## Troubleshooting - -### Common Issues - -| Issue | Cause | Solution | -| ---------------------- | ---------------------------------------- | ------------------------------------------------- | -| "Not Available" Error | iOS version < 13 or not configured | Check device compatibility and configuration | -| Invalid Identity Token | Incorrect Nhost Apple configuration | Verify Apple provider settings in Nhost dashboard | -| Nonce Mismatch | Sending hashed nonce to Nhost | Send original unhashed nonce to Nhost | -| Bundle ID Mismatch | App bundle ID doesn't match Apple config | Ensure bundle IDs match in all configurations | - -### Debug Tools - -```typescript -// Enable debug logging -if (__DEV__) { - console.log("Apple Auth Available:", appleAuthAvailable); - console.log("Generated Nonce:", nonce); - console.log("Hashed Nonce:", hashedNonce); - console.log("Identity Token:", credential.identityToken); -} -``` - -## Related Documentation - -- [Apple Sign-In Setup Guide](./APPLE_SIGN_IN_SETUP.md) -- [Protected Routes & Email Auth](./README_PROTECTED_ROUTES.md) -- [Magic Links](./README_MAGIC_LINKS.md) -- [Social Sign-In](./README_SOCIAL_SIGNIN.md) - -## External Resources - -- [Apple Sign-In Documentation](https://developer.apple.com/sign-in-with-apple/) -- [Expo Apple Authentication](https://docs.expo.dev/versions/latest/sdk/apple-authentication/) -- [Nhost Apple Provider Setup](https://docs.nhost.io/authentication/providers/apple) -- [JWT Token Inspector](https://jwt.io/) - For debugging identity tokens diff --git a/examples/demos/ReactNativeDemo/README_PROTECTED_ROUTES.md b/examples/demos/ReactNativeDemo/README_PROTECTED_ROUTES.md deleted file mode 100644 index 6a6022ff7..000000000 --- a/examples/demos/ReactNativeDemo/README_PROTECTED_ROUTES.md +++ /dev/null @@ -1,357 +0,0 @@ -# Protected Routes & Email Authentication - -This document explains how protected routes and email/password authentication are implemented in the Nhost React Native demo, including multi-factor authentication (MFA) support. - -## Overview - -The app implements a robust authentication system with: - -- Email/password sign-up and sign-in -- Route protection for authenticated users -- Multi-factor authentication (MFA) with TOTP -- Persistent session management -- Automatic redirects for unauthenticated users - -## Authentication Context - -### AuthProvider Implementation - -The `AuthProvider` component wraps the entire app and provides global authentication state: - -```typescript -// app/lib/nhost/AuthProvider.tsx -const AuthProvider = ({ children }: AuthProviderProps) => { - const [user, setUser] = useState(null); - const [session, setSession] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [isAuthenticated, setIsAuthenticated] = useState(false); - - const nhost = useMemo(() => { - const subdomain = - Constants.expoConfig?.extra?.["NHOST_SUBDOMAIN"] || "local"; - const region = Constants.expoConfig?.extra?.["NHOST_REGION"] || "local"; - - return createClient({ - subdomain, - region, - storage: new NhostAsyncStorage(), // Custom AsyncStorage adapter - }); - }, []); - - // Session initialization and change listeners... -}; -``` - -### Key Features - -1. **Session Persistence**: Uses a custom AsyncStorage adapter that works with Nhost's synchronous interface -2. **Automatic State Updates**: Listens for session changes and updates the global state -3. **Loading States**: Manages loading states during authentication operations -4. **Error Handling**: Graceful handling of storage and authentication errors - -## Protected Routes - -### ProtectedScreen Component - -The `ProtectedScreen` component acts as a higher-order component that protects routes: - -```typescript -// app/components/ProtectedScreen.tsx -export default function ProtectedScreen({ - children, - redirectTo = "/signin", -}: ProtectedScreenProps) { - const { isAuthenticated, isLoading } = useAuth(); - - useEffect(() => { - if (!isLoading && !isAuthenticated) { - router.replace(redirectTo); - } - }, [isAuthenticated, isLoading, redirectTo]); - - if (isLoading) { - return ; - } - - if (!isAuthenticated) { - return null; // Will redirect in useEffect - } - - return <>{children}; -} -``` - -### Usage Example - -Protect any screen by wrapping it with `ProtectedScreen`: - -```typescript -// app/profile.tsx -export default function Profile() { - return ( - - - - ); -} -``` - -### Features - -1. **Automatic Redirects**: Unauthenticated users are redirected to sign-in -2. **Loading States**: Shows loading indicator while checking authentication -3. **Customizable Redirect**: Can specify where to redirect unauthenticated users -4. **No Flash**: Prevents showing protected content before redirect - -## Email/Password Authentication - -### Sign Up Flow - -```typescript -// User registration with email and password -const handleSignUp = async () => { - const { error } = await nhost.auth.signUp({ - email, - password, - options: { - displayName, - }, - }); - - if (!error) { - // User created successfully - router.replace("/profile"); - } -}; -``` - -### Sign In Flow - -```typescript -// User authentication with email and password -const handleSignIn = async () => { - const { error, needsEmailVerification, needsMfaOtp } = - await nhost.auth.signInEmailPassword({ - email, - password, - }); - - if (needsEmailVerification) { - setError("Please verify your email before signing in"); - return; - } - - if (needsMfaOtp) { - // Redirect to MFA input screen - setShowMfaInput(true); - return; - } - - if (!error) { - router.replace("/profile"); - } -}; -``` - -## Multi-Factor Authentication (MFA) - -### TOTP Setup - -The app supports Time-based One-Time Password (TOTP) authentication: - -```typescript -// Generate TOTP secret and QR code -const generateMfa = async () => { - const { totpSecret, qrCodeDataUrl } = await nhost.auth.generateMfa(); - - // Display QR code for user to scan with authenticator app - setQrCode(qrCodeDataUrl); - setTotpSecret(totpSecret); -}; -``` - -### MFA Verification - -```typescript -// Verify TOTP code during sign-in -const verifyMfaCode = async () => { - const { error } = await nhost.auth.signInMfaTotp({ - otp: mfaCode, - }); - - if (!error) { - router.replace("/profile"); - } -}; -``` - -### MFA Management - -Users can enable/disable MFA from their profile: - -```typescript -// Enable MFA with TOTP -const enableMfa = async () => { - const { error } = await nhost.auth.enableMfa({ - code: totpCode, - }); -}; - -// Disable MFA -const disableMfa = async () => { - const { error } = await nhost.auth.disableMfa({ - code: totpCode, - }); -}; -``` - -## Session Management - -### Custom AsyncStorage Adapter - -The app uses a custom storage adapter for reliable session persistence: - -```typescript -// app/lib/nhost/AsyncStorage.tsx -export default class NhostAsyncStorage implements Storage { - private cache: Map = new Map(); - - setItem(key: string, value: string): void { - this.cache.set(key, value); - AsyncStorage.setItem(key, value).catch(console.error); - } - - getItem(key: string): string | null { - return this.cache.get(key) || null; - } - - removeItem(key: string): void { - this.cache.delete(key); - AsyncStorage.removeItem(key).catch(console.error); - } -} -``` - -### Features - -1. **In-Memory Cache**: Provides synchronous access for Nhost while using AsyncStorage -2. **Persistence**: Sessions survive app restarts and background/foreground cycles -3. **Error Handling**: Graceful fallback if AsyncStorage operations fail -4. **Expo Go Compatible**: Works reliably in both Expo Go and standalone builds - -## Error Handling - -### Common Authentication Errors - -```typescript -const handleAuthError = (error: any) => { - switch (error?.message) { - case "Invalid email or password": - setError("Please check your email and password"); - break; - case "Email not verified": - setError("Please verify your email before signing in"); - break; - case "Invalid MFA code": - setError("Please enter a valid 6-digit code"); - break; - default: - setError("An unexpected error occurred"); - } -}; -``` - -### Network and Storage Errors - -The app handles various error scenarios: - -- Network connectivity issues -- AsyncStorage failures -- Nhost service unavailability -- Invalid authentication tokens - -## Security Considerations - -### Best Practices Implemented - -1. **Secure Storage**: Sessions are stored securely using AsyncStorage -2. **Token Validation**: Automatic token refresh and validation -3. **Route Protection**: Server-side validation of protected routes -4. **MFA Support**: Additional security layer with TOTP -5. **Session Expiry**: Automatic logout when sessions expire - -### Password Requirements - -Configure password requirements in your Nhost dashboard: - -- Minimum length -- Character complexity -- Common password prevention -- Breach database checking - -## Testing Authentication - -### Test Scenarios - -1. **Valid Credentials**: Test successful sign-in with correct email/password -2. **Invalid Credentials**: Test error handling with wrong credentials -3. **Unverified Email**: Test flow for users who haven't verified email -4. **MFA Flow**: Test sign-in with MFA enabled -5. **Session Persistence**: Test app restart with active session -6. **Network Errors**: Test offline scenarios and poor connectivity - -### Debug Tools - -Enable debug mode to see authentication state changes: - -```typescript -// Add to AuthProvider for debugging -useEffect(() => { - if (__DEV__) { - console.log("Auth state changed:", { isAuthenticated, user: user?.email }); - } -}, [isAuthenticated, user]); -``` - -## Configuration - -### Required Setup - -1. **Email Provider**: Configure email provider in Nhost dashboard -2. **Email Templates**: Customize verification and welcome emails -3. **Password Policy**: Set password requirements -4. **MFA Settings**: Enable TOTP in authentication settings - -### Environment Variables - -```json -// app.json -{ - "extra": { - "NHOST_SUBDOMAIN": "your-project-subdomain", - "NHOST_REGION": "your-region" - } -} -``` - -## Troubleshooting - -### Common Issues - -1. **Session Not Persisting**: Check AsyncStorage permissions and implementation -2. **Infinite Loading**: Verify Nhost configuration and network connectivity -3. **MFA Not Working**: Ensure time synchronization between device and server -4. **Redirect Loops**: Check protected route logic and authentication state - -### Debug Steps - -1. Check console logs for authentication errors -2. Verify Nhost dashboard configuration -3. Test with simple email/password flow first -4. Gradually add complexity (MFA, protected routes) - -## Related Documentation - -- [Native Authentication](./README_NATIVE_AUTHENTICATION.md) -- [Magic Links](./README_MAGIC_LINKS.md) -- [Social Sign-In](./README_SOCIAL_SIGNIN.md) diff --git a/examples/demos/ReactNativeDemo/README_SOCIAL_SIGNIN.md b/examples/demos/ReactNativeDemo/README_SOCIAL_SIGNIN.md deleted file mode 100644 index 5a0d832ea..000000000 --- a/examples/demos/ReactNativeDemo/README_SOCIAL_SIGNIN.md +++ /dev/null @@ -1,530 +0,0 @@ -# Social Sign-In with GitHub - -This document explains how social authentication with GitHub is implemented in the Nhost React Native demo, including OAuth flow, deep linking, verification endpoints, and configuration requirements. - -## Overview - -Social sign-in with GitHub provides users with a seamless authentication experience using their existing GitHub accounts. The implementation handles OAuth 2.0 flow, deep linking for mobile apps, and secure token exchange through Nhost's authentication system. - -## OAuth 2.0 Flow - -### Authentication Process - -1. **OAuth Initiation**: App redirects user to GitHub OAuth page -2. **User Authorization**: User grants permissions to the app on GitHub -3. **Authorization Code**: GitHub redirects back with authorization code -4. **Token Exchange**: Nhost exchanges code for access token -5. **User Profile**: Nhost fetches user profile from GitHub -6. **Session Creation**: Nhost creates authenticated session for the user - -## Implementation Details - -### SocialLoginForm Component - -```typescript -// app/components/SocialLoginForm.tsx -export default function SocialLoginForm({ - action, - isLoading: initialLoading = false, -}: SocialLoginFormProps) { - const { nhost } = useAuth(); - const [isLoading] = useState(initialLoading); - - const handleSocialLogin = (provider: "github") => { - // Create redirect URL for current environment - const redirectUrl = Linking.createURL("verify"); - - // Generate OAuth URL with provider and redirect - const url = nhost.auth.signInProviderURL(provider, { - redirectTo: redirectUrl, - }); - - // Open GitHub OAuth in system browser - void Linking.openURL(url); - }; - - return ( - - - {action} using your Social account - - - handleSocialLogin("github")} - disabled={isLoading} - > - - - Continue with GitHub - - - - ); -} -``` - -### Key Features - -1. **Dynamic URL Generation**: Automatically creates correct redirect URLs for different environments -2. **Provider Flexibility**: Easily extensible to support additional OAuth providers -3. **Visual Feedback**: Loading states and branded buttons for better UX -4. **Error Handling**: Graceful handling of OAuth failures and cancellations - -## Deep Linking Configuration - -### URL Scheme Setup - -The app supports deep linking to handle OAuth redirects: - -```json -// app.json -{ - "expo": { - "scheme": "reactnativewebdemo", - "ios": { - "infoPlist": { - "CFBundleURLTypes": [ - { - "CFBundleURLSchemes": ["reactnativewebdemo"] - } - ] - } - } - } -} -``` - -### Redirect URL Formats - -#### Standalone App - -``` -reactnativewebdemo://verify?refreshToken=abc123...&type=signup -``` - -#### Expo Go Development - -``` -exp://192.168.1.103:19000/--/verify?refreshToken=abc123...&type=signup -``` - -### Environment-Aware URL Generation - -```typescript -// Automatically handles environment differences -const redirectUrl = Linking.createURL("verify"); - -// Creates appropriate URL for current environment: -// - Expo Go: exp://host:port/--/verify -// - Standalone: reactnativewebdemo://verify -``` - -## GitHub OAuth Configuration - -### Nhost Dashboard Setup - -Configure GitHub as an OAuth provider in your Nhost dashboard: - -1. **Provider**: Enable GitHub in Authentication > Providers -2. **Client ID**: GitHub OAuth App Client ID -3. **Client Secret**: GitHub OAuth App Client Secret -4. **Redirect URL**: Configure allowed redirect URLs - -### GitHub OAuth App Setup - -Create a GitHub OAuth App in your GitHub Developer Settings: - -1. **Application Name**: Your app name -2. **Homepage URL**: Your app's homepage -3. **Authorization Callback URL**: - - Development: `https://local.auth.nhost.run/v1/auth/providers/github/callback` - - Production: `https://[subdomain].auth.[region].nhost.run/v1/auth/providers/github/callback` - -### Required GitHub Scopes - -The app requests these GitHub scopes: - -- `user:email` - Access to user's email addresses -- `read:user` - Access to user profile information - -## Verification Flow - -### Verify Screen Implementation - -```typescript -// app/verify.tsx - Handles both magic links and social auth -export default function Verify() { - const params = useLocalSearchParams<{ - refreshToken: string; - type?: string; - }>(); - const [status, setStatus] = useState<"verifying" | "success" | "error">( - "verifying", - ); - const { nhost, isAuthenticated } = useAuth(); - - useEffect(() => { - const { refreshToken, type } = params; - - if (!refreshToken) { - setStatus("error"); - setError("No authentication token found"); - return; - } - - async function processAuthentication(): Promise { - try { - // Show verifying state briefly - await new Promise((resolve) => setTimeout(resolve, 500)); - - // Authenticate using refresh token from OAuth flow - await nhost.auth.refreshToken({ refreshToken }); - - setStatus("success"); - - // Redirect after showing success message - setTimeout(() => { - router.replace("/profile"); - }, 1500); - } catch (err) { - setStatus("error"); - setError(`Authentication failed: ${err.message}`); - } - } - - processAuthentication(); - }, [params, nhost.auth]); - - // Redirect if already authenticated - useEffect(() => { - if (isAuthenticated && status !== "verifying") { - router.replace("/profile"); - } - }, [isAuthenticated, status]); - - // ... UI implementation for different states -} -``` - -### Authentication States - -1. **Verifying**: Processing OAuth callback and exchanging tokens -2. **Success**: Authentication completed successfully -3. **Error**: OAuth flow failed or was cancelled - -## User Data Handling - -### GitHub Profile Information - -When users authenticate with GitHub, Nhost receives: - -```typescript -// User profile data from GitHub -interface GitHubUser { - id: string; - email: string; - displayName: string; - avatarUrl?: string; - metadata: { - github: { - id: number; - login: string; - name: string; - company?: string; - blog?: string; - location?: string; - bio?: string; - public_repos: number; - followers: number; - following: number; - created_at: string; - }; - }; -} -``` - -### Accessing User Data - -```typescript -// Access GitHub-specific user data -const { user } = useAuth(); - -if (user?.metadata?.github) { - const githubData = user.metadata.github; - console.log("GitHub username:", githubData.login); - console.log("Public repos:", githubData.public_repos); - console.log("Followers:", githubData.followers); -} -``` - -## Error Handling - -### OAuth Flow Errors - -```typescript -// Common OAuth error scenarios -const handleOAuthErrors = (error: any) => { - switch (error.type) { - case "access_denied": - // User denied permission - Alert.alert("Access Denied", "You need to grant permission to continue"); - break; - - case "invalid_request": - // Malformed OAuth request - Alert.alert("Error", "Invalid authentication request"); - break; - - case "server_error": - // GitHub server error - Alert.alert("Error", "GitHub is temporarily unavailable"); - break; - - case "temporarily_unavailable": - // Service temporarily unavailable - Alert.alert("Error", "Authentication service is busy. Please try again."); - break; - - default: - Alert.alert("Error", "Authentication failed. Please try again."); - } -}; -``` - -### Network and Integration Errors - -```typescript -// Handle Nhost integration errors -const processOAuthCallback = async (refreshToken: string) => { - try { - await nhost.auth.refreshToken({ refreshToken }); - } catch (error) { - if (error.message.includes("Invalid refresh token")) { - throw new Error("Authentication session expired. Please try again."); - } - - if (error.message.includes("Network")) { - throw new Error("Network error. Please check your connection."); - } - - throw new Error("Authentication failed. Please try again."); - } -}; -``` - -## Testing Social Authentication - -### Development Testing - -1. **Start Development Server**: - - ```bash - npx expo start - ``` - -2. **Configure Test Environment**: - - - Ensure GitHub OAuth app has correct callback URL - - Verify Nhost GitHub provider configuration - - Check network connectivity between device and development server - -3. **Test OAuth Flow**: - - Tap "Continue with GitHub" button - - Should open system browser with GitHub OAuth page - - Log in with GitHub credentials - - Grant permissions to the app - - Should redirect back to app and authenticate - -### Test Scenarios - -```typescript -// Test different OAuth scenarios -const testScenarios = [ - "First-time GitHub authentication", - "Returning GitHub user", - "User cancels OAuth flow", - "User denies permissions", - "GitHub account with 2FA enabled", - "Network connection issues during OAuth", - "Invalid OAuth configuration", - "Expired OAuth session", -]; -``` - -### Manual Testing Checklist - -- [ ] GitHub OAuth button appears and is clickable -- [ ] Clicking button opens system browser -- [ ] GitHub login page loads correctly -- [ ] Successfully logging in redirects back to app -- [ ] App shows verification screen briefly -- [ ] User is redirected to profile after authentication -- [ ] User data is correctly populated from GitHub -- [ ] Canceling OAuth flow handles gracefully -- [ ] Network errors are handled appropriately - -## Security Considerations - -### OAuth Security Best Practices - -1. **HTTPS Only**: All OAuth URLs use HTTPS for secure communication -2. **State Parameter**: Nhost includes state parameter to prevent CSRF attacks -3. **Short-Lived Tokens**: Authorization codes have short expiration times -4. **Secure Storage**: Refresh tokens are stored securely by Nhost -5. **Scope Limitation**: Only request necessary permissions from GitHub - -### Token Security - -```typescript -// Nhost handles secure token management -// - Authorization codes are exchanged server-side -// - Access tokens are not exposed to client -// - Refresh tokens are securely stored -// - Session management is handled automatically -``` - -## Troubleshooting - -### Common Issues - -| Issue | Symptom | Solution | -| ---------------------------- | --------------------------------------- | ---------------------------------------------------------------- | -| OAuth redirect doesn't work | Browser opens but doesn't return to app | Check URL scheme configuration and GitHub OAuth app callback URL | -| "Invalid client" error | GitHub shows OAuth error page | Verify GitHub OAuth app Client ID in Nhost dashboard | -| "Redirect URI mismatch" | GitHub rejects OAuth request | Ensure callback URL in GitHub app matches Nhost configuration | -| App doesn't open after OAuth | Browser stays open after GitHub login | Check deep linking configuration and app installation | - -### Debug Steps - -1. **Check OAuth URL**: - - ```typescript - const url = nhost.auth.signInProviderURL("github", { - redirectTo: redirectUrl, - }); - console.log("OAuth URL:", url); - ``` - -2. **Verify Redirect URL**: - - ```typescript - const redirectUrl = Linking.createURL("verify"); - console.log("Redirect URL:", redirectUrl); - ``` - -3. **Check URL Parameters**: - - ```typescript - // In verify screen - console.log("Received parameters:", params); - ``` - -4. **Test Manual URL**: - - Copy OAuth URL from console - - Paste into browser to test flow manually - -### GitHub-Specific Debugging - -1. **Check GitHub OAuth App Settings**: - - - Verify callback URLs are correctly configured - - Ensure app is not suspended or restricted - -2. **Monitor GitHub OAuth Logs**: - - - Check GitHub OAuth app's activity logs - - Look for failed authorization attempts - -3. **Validate GitHub Scopes**: - - Ensure requested scopes match app requirements - - Check if user has granted necessary permissions - -## Production Deployment - -### GitHub OAuth App Configuration - -For production deployment: - -1. **Production Callback URL**: - - ``` - https://[subdomain].auth.[region].nhost.run/v1/auth/providers/github/callback - ``` - -2. **Homepage URL**: Set to your production app's homepage - -3. **Application Description**: Provide clear description of your app's purpose - -### Universal Links Setup - -Configure universal links for seamless production experience: - -```json -// apple-app-site-association (iOS) -{ - "applinks": { - "apps": [], - "details": [ - { - "appID": "TEAMID.com.nhost.reactnativewebdemo", - "paths": ["/verify*", "/auth/callback*"] - } - ] - } -} -``` - -### Security Hardening - -1. **Environment Variables**: Store sensitive OAuth credentials securely -2. **Domain Validation**: Implement additional domain validation for callbacks -3. **Rate Limiting**: Configure rate limiting for OAuth endpoints -4. **Monitoring**: Set up monitoring for failed OAuth attempts - -## Extending to Other Providers - -### Adding New OAuth Providers - -The implementation can be easily extended to support other providers: - -```typescript -// Extended provider support -type SocialProvider = "github" | "google" | "facebook" | "discord"; - -const handleSocialLogin = (provider: SocialProvider) => { - const redirectUrl = Linking.createURL("verify"); - const url = nhost.auth.signInProviderURL(provider, { - redirectTo: redirectUrl, - }); - void Linking.openURL(url); -}; - -// Provider-specific UI -const getProviderIcon = (provider: SocialProvider) => { - switch (provider) { - case "github": - return "logo-github"; - case "google": - return "logo-google"; - case "facebook": - return "logo-facebook"; - case "discord": - return "logo-discord"; - } -}; -``` - -## Related Documentation - -- [Protected Routes & Email Auth](./README_PROTECTED_ROUTES.md) -- [Native Authentication](./README_NATIVE_AUTHENTICATION.md) -- [Magic Links](./README_MAGIC_LINKS.md) - -## External Resources - -- [GitHub OAuth Documentation](https://docs.github.com/en/developers/apps/building-oauth-apps) -- [Nhost Social Authentication](https://docs.nhost.io/authentication/social-login) -- [OAuth 2.0 Security Best Practices](https://tools.ietf.org/html/draft-ietf-oauth-security-topics) -- [Expo AuthSession](https://docs.expo.dev/versions/latest/sdk/auth-session/) -- [React Native Deep Linking](https://reactnative.dev/docs/linking) diff --git a/examples/demos/ReactNativeDemo/app.json b/examples/demos/ReactNativeDemo/app.json deleted file mode 100644 index 90001b59c..000000000 --- a/examples/demos/ReactNativeDemo/app.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "expo": { - "name": "ReactNativeWebDemo", - "slug": "ReactNativeWebDemo", - "version": "1.0.0", - "orientation": "portrait", - "icon": "./assets/images/icon.png", - "scheme": "reactnativewebdemo", - "userInterfaceStyle": "automatic", - "newArchEnabled": true, - "ios": { - "supportsTablet": true, - "bundleIdentifier": "com.nhost.reactnativewebdemo", - "jsEngine": "jsc", - "infoPlist": { - "NSFaceIDUsageDescription": "This app uses Face ID for signing in", - "CFBundleURLTypes": [ - { - "CFBundleURLSchemes": ["reactnativewebdemo"] - } - ] - } - }, - "android": { - "jsEngine": "jsc", - "adaptiveIcon": { - "foregroundImage": "./assets/images/adaptive-icon.png", - "backgroundColor": "#ffffff" - }, - "edgeToEdgeEnabled": true - }, - "plugins": [ - "expo-router", - [ - "expo-splash-screen", - { - "image": "./assets/images/splash-icon.png", - "imageWidth": 200, - "resizeMode": "contain", - "backgroundColor": "#ffffff" - } - ], - ["expo-apple-authentication"] - ], - "experiments": { - "typedRoutes": true - }, - "extra": { - "NHOST_REGION": "local", - "NHOST_SUBDOMAIN": "192-168-1-103" - } - } -} diff --git a/examples/demos/ReactNativeDemo/app/_layout.tsx b/examples/demos/ReactNativeDemo/app/_layout.tsx deleted file mode 100644 index 7b39c1a1f..000000000 --- a/examples/demos/ReactNativeDemo/app/_layout.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Stack } from "expo-router"; -import { Text, View } from "react-native"; -import { AuthProvider } from "./lib/nhost/AuthProvider"; - -export default function RootLayout() { - return ( - - - - - - - - - - - - ); -} - -// Error boundary to catch and display errors -export function ErrorBoundary(props: { error: Error }) { - return ( - - - An error occurred - - - {props.error.message} - - {props.error.stack} - - ); -} diff --git a/examples/demos/ReactNativeDemo/app/components/AppleSignIn.tsx b/examples/demos/ReactNativeDemo/app/components/AppleSignIn.tsx deleted file mode 100644 index fee9dc6c8..000000000 --- a/examples/demos/ReactNativeDemo/app/components/AppleSignIn.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import * as AppleAuthentication from "expo-apple-authentication"; -import * as Crypto from "expo-crypto"; -import { router } from "expo-router"; -import React from "react"; -import { Alert, Platform, StyleSheet } from "react-native"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface AppleSignInProps { - action: "Sign In" | "Sign Up"; - isLoading: boolean; - setIsLoading: (isLoading: boolean) => void; -} - -const AppleSignIn: React.FC = ({ setIsLoading }) => { - const { nhost } = useAuth(); - - // Check if Apple authentication is available on this device - const [appleAuthAvailable, setAppleAuthAvailable] = React.useState(false); - - React.useEffect(() => { - const checkAvailability = async () => { - if (Platform.OS === "ios") { - const isAvailable = await AppleAuthentication.isAvailableAsync(); - setAppleAuthAvailable(isAvailable); - } - }; - - void checkAvailability(); - }, []); - - const handleAppleSignIn = async () => { - try { - setIsLoading(true); - - const nonce = Math.random().toString(36).substring(2, 15); - - // Hash the nonce for Apple Authentication - const hashedNonce = await Crypto.digestStringAsync( - Crypto.CryptoDigestAlgorithm.SHA256, - nonce, - ); - - // Request Apple authentication with our hashed nonce - const credential = await AppleAuthentication.signInAsync({ - requestedScopes: [ - AppleAuthentication.AppleAuthenticationScope.FULL_NAME, - AppleAuthentication.AppleAuthenticationScope.EMAIL, - ], - nonce: hashedNonce, - }); - - if (credential.identityToken) { - // Use the identity token to sign in with Nhost - // Pass the original unhashed nonce to the SDK - // so the server can verify it - const response = await nhost.auth.signInIdToken({ - provider: "apple", - idToken: credential.identityToken, - nonce, - }); - - if (response.body?.session) { - router.replace("/profile"); - } else { - Alert.alert( - "Authentication Error", - "Failed to authenticate with Nhost", - ); - } - } else { - Alert.alert( - "Authentication Error", - "No identity token received from Apple", - ); - } - } catch (error: unknown) { - // Handle other errors - const message = - error instanceof Error - ? error.message - : "Failed to authentica with Apple"; - Alert.alert("Authentication Error", message); - } finally { - setIsLoading(false); - } - }; - - // Only show the button on iOS devices where Apple authentication is available - if (Platform.OS !== "ios" || !appleAuthAvailable) { - return null; - } - - return ( - - ); -}; - -const styles = StyleSheet.create({ - appleButton: { - width: "100%", - height: 45, - marginBottom: 10, - }, -}); - -export default AppleSignIn; diff --git a/examples/demos/ReactNativeDemo/app/components/MFASettings.tsx b/examples/demos/ReactNativeDemo/app/components/MFASettings.tsx deleted file mode 100644 index c55569ed4..000000000 --- a/examples/demos/ReactNativeDemo/app/components/MFASettings.tsx +++ /dev/null @@ -1,594 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import * as Clipboard from "expo-clipboard"; -import { useEffect, useState } from "react"; -import { - ActivityIndicator, - Alert, - Dimensions, - Image, - Keyboard, - KeyboardAvoidingView, - Modal, - ScrollView, - StyleSheet, - Text, - TextInput, - TouchableOpacity, - TouchableWithoutFeedback, - View, -} from "react-native"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface MFASettingsProps { - initialMfaEnabled: boolean; -} - -export default function MFASettings({ initialMfaEnabled }: MFASettingsProps) { - const [isMfaEnabled, setIsMfaEnabled] = useState(initialMfaEnabled); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [success, setSuccess] = useState(null); - const { nhost } = useAuth(); - - // Update internal state when prop changes - useEffect(() => { - if (initialMfaEnabled !== isMfaEnabled) { - setIsMfaEnabled(initialMfaEnabled); - } - }, [initialMfaEnabled, isMfaEnabled]); - - // MFA setup states - const [isSettingUpMfa, setIsSettingUpMfa] = useState(false); - const [totpSecret, setTotpSecret] = useState(""); - const [qrCodeUrl, setQrCodeUrl] = useState(""); - const [verificationCode, setVerificationCode] = useState(""); - const [qrCodeModalVisible, setQrCodeModalVisible] = useState(false); - - // Disabling MFA states - const [isDisablingMfa, setIsDisablingMfa] = useState(false); - const [disableVerificationCode, setDisableVerificationCode] = - useState(""); - - // Begin MFA setup process - const handleEnableMfa = async () => { - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Generate TOTP secret - const response = await nhost.auth.changeUserMfa(); - setTotpSecret(response.body.totpSecret); - setQrCodeUrl(response.body.imageUrl); - setIsSettingUpMfa(true); - } catch (err) { - const errMessage = err instanceof Error ? err.message : "Unknown error"; - setError(`An error occurred while enabling MFA: ${errMessage}`); - Alert.alert("Error", `Failed to enable MFA: ${errMessage}`); - } finally { - setIsLoading(false); - } - }; - - // Verify TOTP and enable MFA - const handleVerifyTotp = async () => { - if (!verificationCode) { - setError("Please enter the verification code"); - Alert.alert("Error", "Please enter the verification code"); - return; - } - - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Verify and activate MFA - await nhost.auth.verifyChangeUserMfa({ - activeMfaType: "totp", - code: verificationCode, - }); - - setIsMfaEnabled(true); - setIsSettingUpMfa(false); - setSuccess("MFA has been successfully enabled."); - Alert.alert("Success", "MFA has been successfully enabled."); - } catch (err) { - const errMessage = err instanceof Error ? err.message : "Unknown error"; - setError(`An error occurred while verifying the code: ${errMessage}`); - Alert.alert("Error", `Failed to verify code: ${errMessage}`); - } finally { - setIsLoading(false); - } - }; - - // Show disable MFA confirmation - const handleShowDisableMfa = () => { - setIsDisablingMfa(true); - setError(null); - setSuccess(null); - }; - - // Disable MFA - const handleDisableMfa = async () => { - if (!disableVerificationCode) { - setError("Please enter your verification code to confirm"); - Alert.alert("Error", "Please enter your verification code to confirm"); - return; - } - - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Disable MFA by setting activeMfaType to empty string - await nhost.auth.verifyChangeUserMfa({ - activeMfaType: "", - code: disableVerificationCode, - }); - - setIsMfaEnabled(false); - setIsDisablingMfa(false); - setDisableVerificationCode(""); - setSuccess("MFA has been successfully disabled."); - Alert.alert("Success", "MFA has been successfully disabled."); - } catch (err) { - const error = err as FetchError; - setError(`An error occurred while disabling MFA: ${error.message}`); - Alert.alert("Error", `Failed to disable MFA: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - // Cancel MFA setup - const handleCancelMfaSetup = () => { - setIsSettingUpMfa(false); - setTotpSecret(""); - setQrCodeUrl(""); - setVerificationCode(""); - }; - - // Cancel MFA disable - const handleCancelMfaDisable = () => { - setIsDisablingMfa(false); - setDisableVerificationCode(""); - setError(null); - }; - - return ( - - Multi-Factor Authentication - - {error && ( - - {error} - - )} - - {success && ( - - {success} - - )} - - {isSettingUpMfa ? ( - - - - - Scan this QR code with your authenticator app (e.g., Google - Authenticator, Authy): - - - {qrCodeUrl && ( - setQrCodeModalVisible(true)} - > - - (Tap to enlarge) - - )} - - setQrCodeModalVisible(false)} - > - - - Scan QR Code - - setQrCodeModalVisible(false)} - > - Close - - - - - - - Or manually enter this secret key: - - { - await Clipboard.setStringAsync(totpSecret); - Alert.alert("Copied", "Secret key copied to clipboard"); - }} - > - {totpSecret} - (Tap to copy) - - - - Verification Code - - - - - - {isLoading ? ( - - ) : ( - Verify and Enable - )} - - - - Cancel - - - - - - ) : isDisablingMfa ? ( - - - - - To disable Multi-Factor Authentication, please enter the current - verification code from your authenticator app. - - - - Current Verification Code - - - - - - {isLoading ? ( - - ) : ( - Confirm Disable - )} - - - - Cancel - - - - - - ) : ( - - - Multi-Factor Authentication adds an extra layer of security to your - account by requiring a verification code from your authenticator app - when signing in. - - - - Status: - - {isMfaEnabled ? "Enabled" : "Disabled"} - - - - {isMfaEnabled ? ( - - {isLoading ? ( - - ) : ( - Disable MFA - )} - - ) : ( - - {isLoading ? ( - - ) : ( - Enable MFA - )} - - )} - - )} - - ); -} - -const styles = StyleSheet.create({ - container: { - backgroundColor: "#fff", - borderRadius: 10, - padding: 16, - marginBottom: 20, - shadowColor: "#000", - shadowOffset: { - width: 0, - height: 2, - }, - shadowOpacity: 0.1, - shadowRadius: 3.84, - elevation: 5, - flex: 1, - }, - title: { - fontSize: 18, - fontWeight: "bold", - marginBottom: 16, - color: "#333", - }, - contentContainer: { - marginTop: 10, - }, - errorContainer: { - backgroundColor: "#fee2e2", - padding: 12, - borderRadius: 6, - marginBottom: 16, - borderLeftWidth: 4, - borderLeftColor: "#ef4444", - }, - errorText: { - color: "#b91c1c", - fontSize: 14, - }, - successContainer: { - backgroundColor: "#dcfce7", - padding: 12, - borderRadius: 6, - marginBottom: 16, - borderLeftWidth: 4, - borderLeftColor: "#10b981", - }, - successText: { - color: "#047857", - fontSize: 14, - }, - instructionText: { - fontSize: 14, - color: "#4b5563", - marginBottom: 16, - }, - qrCodeContainer: { - alignItems: "center", - justifyContent: "center", - backgroundColor: "#fff", - padding: 10, - marginVertical: 16, - borderRadius: 8, - borderWidth: 1, - borderColor: "#e5e7eb", - }, - qrCode: { - width: 200, - height: 200, - }, - modalOverlay: { - flex: 1, - backgroundColor: "rgba(0,0,0,0.5)", - justifyContent: "center", - alignItems: "center", - }, - modalContent: { - backgroundColor: "white", - borderRadius: 12, - padding: 20, - alignItems: "center", - elevation: 5, - shadowColor: "#000", - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.25, - shadowRadius: 3.84, - width: Dimensions.get("window").width * 0.9, - }, - largeQrCode: { - width: Dimensions.get("window").width * 0.7, - height: Dimensions.get("window").width * 0.7, - marginVertical: 20, - }, - modalTitle: { - fontSize: 18, - fontWeight: "bold", - marginBottom: 15, - }, - closeButton: { - backgroundColor: "#6366f1", - paddingVertical: 12, - paddingHorizontal: 30, - borderRadius: 6, - }, - closeButtonText: { - color: "white", - fontWeight: "600", - }, - secretContainer: { - backgroundColor: "#f3f4f6", - padding: 12, - borderRadius: 6, - marginBottom: 16, - alignItems: "center", - borderWidth: 1, - borderColor: "#d1d5db", - borderStyle: "dashed", - }, - secretText: { - fontFamily: "monospace", - fontSize: 14, - color: "#111827", - marginBottom: 4, - }, - copyHint: { - fontSize: 12, - color: "#6366f1", - fontStyle: "italic", - }, - inputContainer: { - marginBottom: 16, - }, - label: { - fontSize: 14, - fontWeight: "500", - marginBottom: 8, - color: "#374151", - }, - input: { - borderWidth: 1, - borderColor: "#d1d5db", - borderRadius: 6, - padding: 10, - fontSize: 16, - backgroundColor: "#f9fafb", - }, - buttonRow: { - flexDirection: "row", - justifyContent: "space-between", - marginTop: 8, - }, - button: { - flex: 1, - padding: 12, - borderRadius: 6, - alignItems: "center", - justifyContent: "center", - }, - primaryButton: { - backgroundColor: "#6366f1", - marginRight: 8, - }, - secondaryButton: { - backgroundColor: "#f3f4f6", - marginLeft: 8, - borderWidth: 1, - borderColor: "#d1d5db", - }, - disabledButton: { - opacity: 0.5, - }, - buttonText: { - color: "#fff", - fontWeight: "600", - fontSize: 14, - }, - secondaryButtonText: { - color: "#4b5563", - fontWeight: "600", - fontSize: 14, - }, - statusContainer: { - flexDirection: "row", - alignItems: "center", - marginBottom: 20, - }, - statusLabel: { - fontSize: 14, - color: "#4b5563", - marginRight: 8, - }, - statusValue: { - fontSize: 14, - fontWeight: "600", - }, - enabledText: { - color: "#10b981", - }, - disabledText: { - color: "#f59e0b", - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/components/MagicLinkForm.tsx b/examples/demos/ReactNativeDemo/app/components/MagicLinkForm.tsx deleted file mode 100644 index 112c3e678..000000000 --- a/examples/demos/ReactNativeDemo/app/components/MagicLinkForm.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import * as Linking from "expo-linking"; -import { useState } from "react"; -import { - ActivityIndicator, - StyleSheet, - Text, - TextInput, - TouchableOpacity, - View, -} from "react-native"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface MagicLinkFormProps { - buttonLabel?: string; -} - -export default function MagicLinkForm({ - buttonLabel = "Send Magic Link", -}: MagicLinkFormProps) { - const [email, setEmail] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [success, setSuccess] = useState(false); - const [error, setError] = useState(null); - const { nhost } = useAuth(); - - const handleSubmit = async () => { - setIsLoading(true); - setError(null); - - try { - // For Expo Go, we need to create the correct URL format - // This will work both in Expo Go and standalone app - const redirectUrl = Linking.createURL("verify"); - - await nhost.auth.signInPasswordlessEmail({ - email, - options: { - redirectTo: redirectUrl, - }, - }); - - setSuccess(true); - } catch (err) { - const error = err as FetchError; - setError( - `An error occurred while sending the magic link: ${error.message}`, - ); - } finally { - setIsLoading(false); - } - }; - - if (success) { - return ( - - - Magic link sent! Check your email to sign in. - - setSuccess(false)} - > - Try again - - - ); - } - - return ( - - - Email - - - - {error && {error}} - - - {isLoading ? ( - - ) : ( - {buttonLabel} - )} - - - ); -} - -const styles = StyleSheet.create({ - container: { - width: "100%", - }, - inputGroup: { - marginBottom: 15, - }, - label: { - fontSize: 16, - marginBottom: 5, - color: "#333", - }, - input: { - height: 45, - borderWidth: 1, - borderColor: "#ddd", - borderRadius: 5, - paddingHorizontal: 10, - fontSize: 16, - backgroundColor: "#fafafa", - }, - errorText: { - color: "#e53e3e", - marginBottom: 10, - }, - successText: { - fontSize: 16, - color: "#38a169", - textAlign: "center", - marginBottom: 15, - }, - button: { - backgroundColor: "#6366f1", - paddingVertical: 12, - borderRadius: 5, - alignItems: "center", - marginTop: 10, - }, - buttonText: { - color: "#fff", - fontSize: 16, - fontWeight: "600", - }, - secondaryButton: { - backgroundColor: "#e2e8f0", - paddingVertical: 12, - borderRadius: 5, - alignItems: "center", - marginTop: 10, - }, - secondaryButtonText: { - color: "#4a5568", - fontSize: 16, - fontWeight: "600", - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/components/NativeLoginForm.tsx b/examples/demos/ReactNativeDemo/app/components/NativeLoginForm.tsx deleted file mode 100644 index d05101458..000000000 --- a/examples/demos/ReactNativeDemo/app/components/NativeLoginForm.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { - ActivityIndicator, - Platform, - StyleSheet, - Text, - View, -} from "react-native"; -import AppleSignIn from "./AppleSignIn"; - -interface NativeLoginFormProps { - action: "Sign In" | "Sign Up"; - isLoading: boolean; - setAppleAuthInProgress: (inProgress: boolean) => void; -} - -export default function NativeLoginForm({ - action, - isLoading, - setAppleAuthInProgress, -}: NativeLoginFormProps) { - // Function to update loading state - const updateLoadingState = (loading: boolean) => { - if (setAppleAuthInProgress) { - setAppleAuthInProgress(loading); - } - }; - - // Check if we have any native options for this platform - const hasAppleOption = Platform.OS === "ios"; - - return ( - - - {action} using native authentication methods - - {isLoading ? ( - - ) : ( - - - - {!hasAppleOption && ( - - No native authentication options available for your platform - - )} - - {hasAppleOption && ( - - Native sign-in methods provide a more streamlined authentication - experience - - )} - - )} - - ); -} - -const styles = StyleSheet.create({ - container: { - alignItems: "center", - paddingVertical: 10, - width: "100%", - }, - text: { - fontSize: 16, - marginBottom: 20, - textAlign: "center", - color: "#4a5568", - }, - buttonContainer: { - width: "100%", - alignItems: "center", - }, - infoText: { - marginTop: 10, - fontSize: 12, - color: "#718096", - textAlign: "center", - }, - noOptionsText: { - marginTop: 20, - fontSize: 14, - color: "#a0aec0", - textAlign: "center", - fontStyle: "italic", - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/components/ProtectedScreen.tsx b/examples/demos/ReactNativeDemo/app/components/ProtectedScreen.tsx deleted file mode 100644 index 303424668..000000000 --- a/examples/demos/ReactNativeDemo/app/components/ProtectedScreen.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { router } from "expo-router"; -import type React from "react"; -import { useEffect } from "react"; -import { ActivityIndicator, Text, View } from "react-native"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -type AppRoutes = "/" | "/signin" | "/signup" | "/profile"; - -interface ProtectedScreenProps { - children: React.ReactNode; - redirectTo?: AppRoutes; -} - -export default function ProtectedScreen({ - children, - redirectTo = "/signin", -}: ProtectedScreenProps) { - const { isAuthenticated, isLoading } = useAuth(); - - useEffect(() => { - if (!isLoading && !isAuthenticated) { - router.replace(redirectTo); - } - }, [isAuthenticated, isLoading, redirectTo]); - - if (isLoading) { - return ( - - - Loading... - - ); - } - - if (!isAuthenticated) { - return null; // Will redirect in useEffect - } - - return <>{children}; -} diff --git a/examples/demos/ReactNativeDemo/app/components/SocialLoginForm.tsx b/examples/demos/ReactNativeDemo/app/components/SocialLoginForm.tsx deleted file mode 100644 index ff2af559b..000000000 --- a/examples/demos/ReactNativeDemo/app/components/SocialLoginForm.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Ionicons } from "@expo/vector-icons"; -import * as Linking from "expo-linking"; -import { useState } from "react"; -import { - ActivityIndicator, - StyleSheet, - Text, - TouchableOpacity, - View, -} from "react-native"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface SocialLoginFormProps { - action: "Sign In" | "Sign Up"; - isLoading?: boolean; -} - -export default function SocialLoginForm({ - action, - isLoading: initialLoading = false, -}: SocialLoginFormProps) { - const { nhost } = useAuth(); - const [isLoading] = useState(initialLoading); - - const handleSocialLogin = (provider: "github") => { - // Use the same redirect URL approach as the magic link - const redirectUrl = Linking.createURL("verify"); - - // Sign in with the specified provider - const url = nhost.auth.signInProviderURL(provider, { - redirectTo: redirectUrl, - }); - - // Open the URL in browser - void Linking.openURL(url); - }; - - return ( - - {action} using your Social account - {isLoading ? ( - - ) : ( - handleSocialLogin("github")} - disabled={isLoading} - > - - - Continue with GitHub - - - )} - - ); -} - -const styles = StyleSheet.create({ - socialContainer: { - alignItems: "center", - paddingVertical: 10, - }, - socialText: { - fontSize: 16, - marginBottom: 20, - textAlign: "center", - color: "#4a5568", - }, - socialButton: { - backgroundColor: "#24292e", - paddingVertical: 12, - paddingHorizontal: 15, - borderRadius: 5, - width: "100%", - }, - buttonContent: { - flexDirection: "row", - alignItems: "center", - justifyContent: "center", - }, - githubIcon: { - marginRight: 10, - color: "#ffffff", - }, - socialButtonText: { - color: "#ffffff", - fontSize: 16, - fontWeight: "600", - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/index.tsx b/examples/demos/ReactNativeDemo/app/index.tsx deleted file mode 100644 index 3cdfedfb6..000000000 --- a/examples/demos/ReactNativeDemo/app/index.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { useRouter } from "expo-router"; -import { StyleSheet, Text, TouchableOpacity, View } from "react-native"; -import { useAuth } from "./lib/nhost/AuthProvider"; - -export default function Index() { - const router = useRouter(); - const { isAuthenticated, user } = useAuth(); - - return ( - - Nhost SDK Demo - React Native Example - - - {isAuthenticated ? ( - <> - - Welcome back, {user?.displayName || user?.email || "User"}! - - router.push("/profile")} - > - Go to Profile - - router.push("/upload")} - > - File Upload - - - ) : ( - - router.push("/signin")} - > - Sign In - - - router.push("/signup")} - > - Sign Up - - - )} - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: "center", - alignItems: "center", - padding: 20, - backgroundColor: "#f5f5f5", - }, - title: { - fontSize: 28, - fontWeight: "bold", - marginBottom: 8, - color: "#333", - }, - subtitle: { - fontSize: 18, - marginBottom: 30, - color: "#666", - }, - contentContainer: { - width: "100%", - maxWidth: 400, - backgroundColor: "#fff", - borderRadius: 10, - padding: 20, - alignItems: "center", - shadowColor: "#000", - shadowOffset: { - width: 0, - height: 2, - }, - shadowOpacity: 0.1, - shadowRadius: 3.84, - elevation: 5, - }, - welcomeText: { - fontSize: 18, - marginBottom: 20, - textAlign: "center", - }, - buttonContainer: { - width: "100%", - gap: 15, - }, - authButtons: { - width: "100%", - gap: 15, - }, - button: { - backgroundColor: "#6366f1", - paddingVertical: 12, - paddingHorizontal: 20, - borderRadius: 8, - width: "100%", - alignItems: "center", - marginTop: 10, - }, - secondaryButton: { - backgroundColor: "#818cf8", - }, - buttonText: { - color: "#fff", - fontSize: 16, - fontWeight: "600", - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/lib/nhost/AsyncStorage.tsx b/examples/demos/ReactNativeDemo/app/lib/nhost/AsyncStorage.tsx deleted file mode 100644 index 86d6e3489..000000000 --- a/examples/demos/ReactNativeDemo/app/lib/nhost/AsyncStorage.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { - DEFAULT_SESSION_KEY, - type Session, - type SessionStorageBackend, -} from "@nhost/nhost-js/session"; -import AsyncStorage from "@react-native-async-storage/async-storage"; - -/** - * Custom storage implementation for React Native using AsyncStorage - * to persist the Nhost session on the device. - * - * This implementation synchronously works with the SessionStorageBackend interface - * while ensuring reliable persistence with AsyncStorage for Expo Go. - */ -export default class NhostAsyncStorage implements SessionStorageBackend { - private key: string; - private cache: Session | null = null; - - constructor(key: string = DEFAULT_SESSION_KEY) { - this.key = key; - - // Immediately try to load from AsyncStorage - this.loadFromAsyncStorage(); - } - - /** - * Load the session from AsyncStorage synchronously if possible - */ - private loadFromAsyncStorage(): void { - // Try to get cached data from AsyncStorage immediately - try { - AsyncStorage.getItem(this.key) - .then((value) => { - if (value) { - try { - this.cache = JSON.parse(value) as Session; - } catch (error) { - console.warn("Error parsing session from AsyncStorage:", error); - this.cache = null; - } - } - }) - .catch((error) => { - console.warn("Error loading from AsyncStorage:", error); - }); - } catch (error) { - console.warn("AsyncStorage access error:", error); - } - } - - /** - * Gets the session from the in-memory cache - */ - get(): Session | null { - return this.cache; - } - - /** - * Sets the session in the in-memory cache and persists to AsyncStorage - * Ensures the data gets written by using an immediately invoked async function - */ - set(value: Session): void { - // Update cache immediately - this.cache = value; - - // Persist to AsyncStorage with better error handling - void (async () => { - try { - await AsyncStorage.setItem(this.key, JSON.stringify(value)); - } catch (error) { - console.warn("Error saving session to AsyncStorage:", error); - } - })(); - } - - /** - * Removes the session from the in-memory cache and AsyncStorage - * Ensures the data gets removed by using an immediately invoked async function - */ - remove(): void { - // Clear cache immediately - this.cache = null; - - // Remove from AsyncStorage with better error handling - void (async () => { - try { - await AsyncStorage.removeItem(this.key); - } catch (error) { - console.warn("Error removing session from AsyncStorage:", error); - } - })(); - } -} diff --git a/examples/demos/ReactNativeDemo/app/lib/nhost/AuthProvider.tsx b/examples/demos/ReactNativeDemo/app/lib/nhost/AuthProvider.tsx deleted file mode 100644 index eff07cd86..000000000 --- a/examples/demos/ReactNativeDemo/app/lib/nhost/AuthProvider.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { createClient, type NhostClient } from "@nhost/nhost-js"; -import type { Session } from "@nhost/nhost-js/session"; -import Constants from "expo-constants"; -import { - createContext, - type ReactNode, - useContext, - useEffect, - useMemo, - useState, -} from "react"; -import NhostAsyncStorage from "./AsyncStorage"; - -interface AuthContextType { - user: Session["user"] | null; - session: Session | null; - isAuthenticated: boolean; - isLoading: boolean; - nhost: NhostClient; -} - -// Create context for authentication state and nhost client -const AuthContext = createContext(null); - -interface AuthProviderProps { - children: ReactNode; -} - -export const AuthProvider = ({ children }: AuthProviderProps) => { - const [user, setUser] = useState(null); - const [session, setSession] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [isAuthenticated, setIsAuthenticated] = useState(false); - - // Create the nhost client with persistent storage - const nhost = useMemo(() => { - // Get configuration values with type assertion - const subdomain = - (Constants.expoConfig?.extra?.["NHOST_SUBDOMAIN"] as string) || - "192-168-1-103"; - const region = - (Constants.expoConfig?.extra?.["NHOST_REGION"] as string) || "local"; - - return createClient({ - subdomain, - region, - storage: new NhostAsyncStorage(), - }); - }, []); - - useEffect(() => { - // Initialize authentication state - setIsLoading(true); - - // Allow enough time for AsyncStorage to be read and session to be restored - const initializeSession = async () => { - try { - // Let's wait a bit to ensure AsyncStorage has been read - await new Promise((resolve) => setTimeout(resolve, 100)); - - // Now try to get the current session - const currentSession = nhost.getUserSession(); - - setUser(currentSession?.user || null); - setSession(currentSession); - setIsAuthenticated(!!currentSession); - } catch (error) { - console.warn("Error initializing session:", error); - } finally { - setIsLoading(false); - } - }; - - void initializeSession(); - - // Listen for session changes - const unsubscribe = nhost.sessionStorage.onChange((currentSession) => { - setUser(currentSession?.user || null); - setSession(currentSession); - setIsAuthenticated(!!currentSession); - }); - - // Clean up subscription on unmount - return () => { - unsubscribe(); - }; - }, [nhost]); - - // Context value with nhost client directly exposed - const value: AuthContextType = { - user, - session, - isAuthenticated, - isLoading, - nhost, - }; - - return {children}; -}; - -// Custom hook to use the auth context -export const useAuth = (): AuthContextType => { - const context = useContext(AuthContext); - if (!context) { - throw new Error("useAuth must be used within an AuthProvider"); - } - return context; -}; - -export default AuthProvider; diff --git a/examples/demos/ReactNativeDemo/app/lib/utils.ts b/examples/demos/ReactNativeDemo/app/lib/utils.ts deleted file mode 100644 index 12eb8196d..000000000 --- a/examples/demos/ReactNativeDemo/app/lib/utils.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Formats a file size in bytes to a human-readable string - * @param bytes File size in bytes - * @param decimals Number of decimal places to show - * @returns Formatted file size string (e.g., "1.23 MB") - */ -export function formatFileSize(bytes: number, decimals = 2): string { - if (bytes === 0) return "0 Bytes"; - - const k = 1024; - const dm = decimals < 0 ? 0 : decimals; - const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; - - const i = Math.floor(Math.log(bytes) / Math.log(k)); - - return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`; -} - -/** - * Default export to satisfy the Router's requirements - * This utilities file primarily exports helper functions - */ -export default { - formatFileSize, -}; - -/** - * Converts a Blob to a Base64 string - * @param blob The Blob object to convert - * @returns A Promise that resolves to the Base64 string representation of the Blob - */ -export function blobToBase64(blob: Blob): Promise { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onloadend = () => { - const base64data = reader.result as string; - // Remove the data URL prefix (e.g., "data:application/octet-stream;base64,") - const base64Content = base64data.split(",")[1] || ""; - resolve(base64Content); - }; - reader.onerror = reject; - reader.readAsDataURL(blob); - }); -} diff --git a/examples/demos/ReactNativeDemo/app/profile.tsx b/examples/demos/ReactNativeDemo/app/profile.tsx deleted file mode 100644 index 3ad309a14..000000000 --- a/examples/demos/ReactNativeDemo/app/profile.tsx +++ /dev/null @@ -1,262 +0,0 @@ -import { router } from "expo-router"; -import { useEffect, useState } from "react"; -import { - Alert, - ScrollView, - StyleSheet, - Text, - TouchableOpacity, - View, -} from "react-native"; -import MFASettings from "./components/MFASettings"; -import ProtectedScreen from "./components/ProtectedScreen"; -import { useAuth } from "./lib/nhost/AuthProvider"; - -interface MfaStatusResponse { - user?: { - activeMfaType: string | null; - }; -} - -export default function Profile() { - const { nhost, user, session, isAuthenticated } = useAuth(); - const [isMfaEnabled, setIsMfaEnabled] = useState(false); - - // Fetch MFA status when user is authenticated - useEffect(() => { - const fetchMfaStatus = async () => { - if (!user?.id) return; - - try { - // Correctly structure GraphQL query with parameters - const response = await nhost.graphql.request({ - query: ` - query GetUserMfaStatus($userId: uuid!) { - user(id: $userId) { - activeMfaType - } - } - `, - variables: { - userId: user.id, - }, - }); - - const activeMfaType = response.body?.data?.user?.activeMfaType; - const newMfaEnabled = activeMfaType === "totp"; - - // Update the state - setIsMfaEnabled(newMfaEnabled); - } catch (err) { - const errMessage = - err instanceof Error ? err.message : "An unexpected error occurred"; - console.error(`Failed to query MFA status: ${errMessage}`); - } - }; - - if (isAuthenticated && user?.id) { - void fetchMfaStatus(); - } - }, [user, isAuthenticated, nhost.graphql]); - - const handleSignOut = async () => { - try { - const session = nhost.getUserSession(); - if (session) { - await nhost.auth.signOut({ - refreshToken: session.refreshToken, - }); - } - - router.replace("/signin"); - } catch { - Alert.alert("Error", "Failed to sign out"); - } - }; - - return ( - - - Your Profile - - - - Display Name: - - {user?.displayName || "Not set"} - - - - - Email: - - {user?.email || "Not available"} - - - - - User ID: - - {user?.id || "Not available"} - - - - - Roles: - - {user?.roles?.join(", ") || "None"} - - - - - Email Verified: - - {user?.emailVerified ? "Yes" : "No"} - - - - - - Session Information - - Refresh Token ID: - - {session?.refreshTokenId || "None"} - - - Access Token Expires In: - - {session?.accessTokenExpiresIn - ? `${session.accessTokenExpiresIn}s` - : "N/A"} - - - - - - - router.push("/upload")} - > - File Upload - - - - Sign Out - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: "#f5f5f5", - }, - contentContainer: { - padding: 20, - paddingBottom: 40, - }, - title: { - fontSize: 24, - fontWeight: "bold", - marginBottom: 20, - color: "#333", - textAlign: "center", - }, - card: { - backgroundColor: "#fff", - borderRadius: 10, - padding: 16, - marginBottom: 20, - shadowColor: "#000", - shadowOffset: { - width: 0, - height: 2, - }, - shadowOpacity: 0.1, - shadowRadius: 3.84, - elevation: 5, - }, - profileItem: { - paddingVertical: 12, - borderBottomWidth: 1, - borderBottomColor: "#f0f0f0", - }, - itemLabel: { - fontSize: 16, - fontWeight: "bold", - color: "#333", - marginBottom: 4, - }, - itemValue: { - fontSize: 16, - color: "#666", - }, - sectionTitle: { - fontSize: 18, - fontWeight: "bold", - marginBottom: 12, - color: "#333", - }, - sessionInfo: { - backgroundColor: "#f8f8f8", - padding: 12, - borderRadius: 6, - }, - sessionText: { - fontSize: 14, - fontWeight: "500", - color: "#333", - marginBottom: 2, - }, - sessionValue: { - fontSize: 14, - color: "#666", - marginBottom: 10, - fontFamily: "monospace", - }, - actionButton: { - backgroundColor: "#6366f1", - paddingVertical: 12, - paddingHorizontal: 20, - borderRadius: 8, - alignItems: "center", - marginTop: 10, - marginBottom: 10, - }, - actionButtonText: { - color: "#fff", - fontSize: 16, - fontWeight: "600", - }, - signOutButton: { - backgroundColor: "#e53e3e", - paddingVertical: 12, - paddingHorizontal: 20, - borderRadius: 8, - alignItems: "center", - marginTop: 10, - }, - signOutButtonText: { - color: "#fff", - fontSize: 16, - fontWeight: "600", - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/signin.tsx b/examples/demos/ReactNativeDemo/app/signin.tsx deleted file mode 100644 index 936a2d239..000000000 --- a/examples/demos/ReactNativeDemo/app/signin.tsx +++ /dev/null @@ -1,367 +0,0 @@ -import { Link, router, useLocalSearchParams } from "expo-router"; -import React, { useState } from "react"; -import { - ActivityIndicator, - KeyboardAvoidingView, - ScrollView, - StyleSheet, - Text, - TextInput, - TouchableOpacity, - View, -} from "react-native"; -import MagicLinkForm from "./components/MagicLinkForm"; -import NativeLoginForm from "./components/NativeLoginForm"; -import SocialLoginForm from "./components/SocialLoginForm"; -import { useAuth } from "./lib/nhost/AuthProvider"; - -export default function SignIn() { - const { nhost, isAuthenticated } = useAuth(); - const params = useLocalSearchParams(); - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [appleAuthInProgress, setAppleAuthInProgress] = useState(false); - const [error, setError] = useState(null); - const [activeTab, setActiveTab] = useState< - "password" | "magic" | "social" | "native" - >("password"); - - const magicLinkSent = params["magic"] === "success"; - - // If already authenticated, redirect to profile - React.useEffect(() => { - if (isAuthenticated) { - router.replace("/profile"); - } - }, [isAuthenticated]); - - const handleSubmit = async () => { - setIsLoading(true); - setError(null); - - try { - // Use the signIn function from auth context - const response = await nhost.auth.signInEmailPassword({ - email, - password, - }); - - // Check if MFA is required - if (response.body?.mfa) { - router.push(`/signin/mfa?ticket=${response.body.mfa.ticket}`); - return; - } - - // If we have a session, sign in was successful - if (response.body?.session) { - router.replace("/profile"); - } else { - setError("Failed to sign in"); - } - } catch (err) { - const errMessage = - err instanceof Error ? err.message : "An unexpected error occurred"; - setError(`An error occurred during sign in: ${errMessage}`); - } finally { - setIsLoading(false); - } - }; - - return ( - - - Nhost SDK Demo - - - Sign In - - {magicLinkSent ? ( - - - Magic link sent! Check your email to sign in. - - router.setParams({ magic: "" })} - > - Back to sign in - - - ) : ( - <> - - setActiveTab("password")} - > - - Password - - - setActiveTab("magic")} - > - - Magic Link - - - setActiveTab("social")} - > - - Social - - - setActiveTab("native")} - > - - Native - - - - - - {activeTab === "password" ? ( - <> - - Email - - - - - Password - - - - {error && {error}} - - - {isLoading ? ( - - ) : ( - Sign In - )} - - - ) : activeTab === "magic" ? ( - - ) : activeTab === "social" ? ( - - ) : ( - - )} - - - )} - - - - - Don't have an account?{" "} - - Sign Up - - - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: "#f5f5f5", - }, - scrollContainer: { - flexGrow: 1, - justifyContent: "center", - padding: 20, - }, - title: { - fontSize: 24, - fontWeight: "bold", - textAlign: "center", - marginBottom: 20, - color: "#333", - }, - card: { - width: "100%", - maxWidth: 400, - backgroundColor: "#fff", - borderRadius: 10, - padding: 20, - alignSelf: "center", - shadowColor: "#000", - shadowOffset: { - width: 0, - height: 2, - }, - shadowOpacity: 0.1, - shadowRadius: 3.84, - elevation: 5, - }, - cardTitle: { - fontSize: 20, - fontWeight: "bold", - marginBottom: 20, - textAlign: "center", - }, - tabContainer: { - flexDirection: "row", - marginBottom: 20, - borderBottomWidth: 1, - borderBottomColor: "#e2e8f0", - }, - tabButton: { - flex: 1, - paddingVertical: 10, - alignItems: "center", - }, - tabText: { - fontSize: 16, - color: "#718096", - }, - activeTab: { - borderBottomWidth: 2, - borderBottomColor: "#6366f1", - }, - activeTabText: { - color: "#6366f1", - fontWeight: "600", - }, - form: { - width: "100%", - }, - inputGroup: { - marginBottom: 15, - }, - label: { - fontSize: 16, - marginBottom: 5, - color: "#333", - }, - input: { - height: 45, - borderWidth: 1, - borderColor: "#ddd", - borderRadius: 5, - paddingHorizontal: 10, - fontSize: 16, - backgroundColor: "#fafafa", - }, - errorText: { - color: "#e53e3e", - marginBottom: 10, - }, - successText: { - color: "#38a169", - fontSize: 16, - textAlign: "center", - marginBottom: 15, - }, - messageContainer: { - alignItems: "center", - paddingVertical: 10, - }, - button: { - backgroundColor: "#6366f1", - paddingVertical: 12, - borderRadius: 5, - alignItems: "center", - marginTop: 10, - }, - buttonText: { - color: "#fff", - fontSize: 16, - fontWeight: "600", - }, - secondaryButton: { - backgroundColor: "#e2e8f0", - paddingVertical: 12, - paddingHorizontal: 20, - borderRadius: 5, - alignItems: "center", - marginTop: 10, - }, - secondaryButtonText: { - color: "#4a5568", - fontSize: 16, - fontWeight: "600", - }, - footer: { - marginTop: 20, - alignItems: "center", - }, - footerText: { - color: "#666", - fontSize: 14, - }, - link: { - color: "#6366f1", - fontWeight: "bold", - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/signin/mfa.tsx b/examples/demos/ReactNativeDemo/app/signin/mfa.tsx deleted file mode 100644 index 656aa9563..000000000 --- a/examples/demos/ReactNativeDemo/app/signin/mfa.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import { router, useLocalSearchParams } from "expo-router"; -import { useEffect, useState } from "react"; -import { - ActivityIndicator, - Alert, - Keyboard, - KeyboardAvoidingView, - ScrollView, - StyleSheet, - Text, - TextInput, - TouchableOpacity, - TouchableWithoutFeedback, - View, -} from "react-native"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -export default function MFAVerification() { - const { nhost } = useAuth(); - const params = useLocalSearchParams(); - const ticket = params["ticket"] as string; - - const [verificationCode, setVerificationCode] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - - // Redirect if no ticket is provided - useEffect(() => { - if (!ticket) { - Alert.alert("Error", "Invalid authentication request"); - router.replace("/signin"); - } - }, [ticket]); - - const handleSubmit = async () => { - if (!verificationCode || verificationCode.length !== 6) { - setError("Please enter a valid 6-digit code"); - return; - } - - if (!ticket) { - setError("Missing authentication ticket"); - return; - } - - setIsLoading(true); - setError(null); - - try { - // Complete MFA verification - await nhost.auth.verifySignInMfaTotp({ - ticket, - otp: verificationCode, - }); - } catch (err) { - const errMessage = - err instanceof Error ? err.message : "An unexpected error occurred"; - setError(`Verification failed: ${errMessage}`); - } finally { - setIsLoading(false); - } - }; - - return ( - - - - - Multi-Factor Authentication - - - - Enter the verification code from your authenticator app to - complete sign in. - - - {error && ( - - {error} - - )} - - - Authentication Code - { - Keyboard.dismiss(); - if (verificationCode.length === 6 && !isLoading) { - void handleSubmit(); - } - }} - /> - - - - {isLoading ? ( - - ) : ( - Verify - )} - - - router.back()} - disabled={isLoading} - > - Back to Sign In - - - - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: "#f5f5f5", - }, - scrollViewContent: { - flexGrow: 1, - }, - contentContainer: { - flex: 1, - padding: 20, - justifyContent: "center", - paddingBottom: 40, - }, - title: { - fontSize: 24, - fontWeight: "bold", - marginBottom: 20, - textAlign: "center", - color: "#333", - }, - card: { - backgroundColor: "#fff", - borderRadius: 10, - padding: 20, - shadowColor: "#000", - shadowOffset: { - width: 0, - height: 2, - }, - shadowOpacity: 0.1, - shadowRadius: 3.84, - elevation: 5, - }, - instructions: { - fontSize: 16, - color: "#4b5563", - marginBottom: 20, - textAlign: "center", - }, - errorContainer: { - backgroundColor: "#fee2e2", - padding: 12, - borderRadius: 6, - marginBottom: 16, - borderLeftWidth: 4, - borderLeftColor: "#ef4444", - }, - errorText: { - color: "#b91c1c", - }, - inputContainer: { - marginBottom: 20, - }, - label: { - fontSize: 16, - marginBottom: 8, - color: "#374151", - }, - input: { - borderWidth: 1, - borderColor: "#d1d5db", - borderRadius: 6, - padding: 12, - fontSize: 18, - backgroundColor: "#f9fafb", - textAlign: "center", - letterSpacing: 8, - }, - button: { - backgroundColor: "#6366f1", - padding: 15, - borderRadius: 6, - alignItems: "center", - justifyContent: "center", - }, - buttonDisabled: { - opacity: 0.5, - }, - buttonText: { - color: "#fff", - fontWeight: "bold", - fontSize: 16, - }, - backLink: { - marginTop: 20, - alignItems: "center", - }, - backLinkText: { - color: "#6366f1", - fontSize: 16, - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/signup.tsx b/examples/demos/ReactNativeDemo/app/signup.tsx deleted file mode 100644 index a94f3a1c0..000000000 --- a/examples/demos/ReactNativeDemo/app/signup.tsx +++ /dev/null @@ -1,431 +0,0 @@ -import * as Linking from "expo-linking"; -import { Link, router, useLocalSearchParams } from "expo-router"; -import { useEffect, useState } from "react"; -import { - ActivityIndicator, - KeyboardAvoidingView, - ScrollView, - StyleSheet, - Text, - TextInput, - TouchableOpacity, - View, -} from "react-native"; -import MagicLinkForm from "./components/MagicLinkForm"; -import NativeLoginForm from "./components/NativeLoginForm"; -import SocialLoginForm from "./components/SocialLoginForm"; -import { useAuth } from "./lib/nhost/AuthProvider"; - -export default function SignUp() { - const { nhost, isAuthenticated } = useAuth(); - const params = useLocalSearchParams(); - - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [displayName, setDisplayName] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [appleAuthInProgress, setAppleAuthInProgress] = useState(false); - const [error, setError] = useState(null); - const [success, setSuccess] = useState(false); - const [activeTab, setActiveTab] = useState< - "password" | "magic" | "social" | "native" - >("password"); - - const magicLinkSent = params["magic"] === "success"; - - // If already authenticated, redirect to profile - useEffect(() => { - if (isAuthenticated) { - router.replace("/profile"); - } - }, [isAuthenticated]); - - const handleSubmit = async () => { - setIsLoading(true); - setError(null); - setSuccess(false); - - try { - const response = await nhost.auth.signUpEmailPassword({ - email, - password, - options: { - displayName, - redirectTo: Linking.createURL("verify"), - }, - }); - - if (response.body?.session) { - // Successfully signed up and automatically signed in - router.replace("/profile"); - } else { - // Verification email sent - setSuccess(true); - } - } catch (err) { - const errMessage = - err instanceof Error ? err.message : "An unexpected error occurred"; - setError(`An error occurred during sign up: ${errMessage}`); - } finally { - setIsLoading(false); - } - }; - - // Social login is now handled by the SocialLoginForm component - - return ( - - - Nhost SDK Demo - - - {success ? ( - <> - Check Your Email - - - - We've sent a verification link to{" "} - {email} - - - Please check your email and click the verification link to - activate your account. - - - router.replace("/signin")} - > - Back to Sign In - - - - ) : ( - <> - Sign Up - - {magicLinkSent ? ( - - - Magic link sent! Check your email to sign in. - - router.setParams({ magic: "" })} - > - - Back to sign up - - - - ) : ( - <> - - setActiveTab("password")} - > - - Password - - - setActiveTab("magic")} - > - - Magic Link - - - setActiveTab("social")} - > - - Social - - - setActiveTab("native")} - > - - Native - - - - - - {activeTab === "password" ? ( - <> - - Display Name - - - - - Email - - - - - Password - - - Password must be at least 8 characters long - - - - {error && {error}} - - - {isLoading ? ( - - ) : ( - Sign Up - )} - - - ) : activeTab === "magic" ? ( - - ) : activeTab === "social" ? ( - - ) : ( - - )} - - - )} - - )} - - - - - Already have an account?{" "} - - Sign In - - - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: "#f5f5f5", - }, - scrollContainer: { - flexGrow: 1, - justifyContent: "center", - padding: 20, - }, - title: { - fontSize: 24, - fontWeight: "bold", - textAlign: "center", - marginBottom: 20, - color: "#333", - }, - card: { - width: "100%", - maxWidth: 400, - backgroundColor: "#fff", - borderRadius: 10, - padding: 20, - alignSelf: "center", - shadowColor: "#000", - shadowOffset: { - width: 0, - height: 2, - }, - shadowOpacity: 0.1, - shadowRadius: 3.84, - elevation: 5, - }, - cardTitle: { - fontSize: 20, - fontWeight: "bold", - marginBottom: 20, - textAlign: "center", - }, - tabContainer: { - flexDirection: "row", - marginBottom: 20, - borderBottomWidth: 1, - borderBottomColor: "#e2e8f0", - }, - tabButton: { - flex: 1, - paddingVertical: 10, - alignItems: "center", - }, - tabText: { - fontSize: 16, - color: "#718096", - }, - activeTab: { - borderBottomWidth: 2, - borderBottomColor: "#6366f1", - }, - activeTabText: { - color: "#6366f1", - fontWeight: "600", - }, - form: { - width: "100%", - }, - inputGroup: { - marginBottom: 15, - }, - label: { - fontSize: 16, - marginBottom: 5, - color: "#333", - }, - input: { - height: 45, - borderWidth: 1, - borderColor: "#ddd", - borderRadius: 5, - paddingHorizontal: 10, - fontSize: 16, - backgroundColor: "#fafafa", - }, - helperText: { - fontSize: 12, - color: "#666", - marginTop: 3, - }, - errorText: { - color: "#e53e3e", - marginBottom: 10, - }, - successText: { - color: "#38a169", - fontSize: 16, - textAlign: "center", - marginBottom: 15, - }, - successMessageBox: { - backgroundColor: "#f0fff4", - borderColor: "#38a169", - borderWidth: 1, - borderRadius: 8, - padding: 16, - marginBottom: 20, - }, - emailText: { - fontWeight: "bold", - color: "#2d3748", - }, - messageContainer: { - alignItems: "center", - paddingVertical: 10, - }, - button: { - backgroundColor: "#6366f1", - paddingVertical: 12, - borderRadius: 5, - alignItems: "center", - marginTop: 10, - }, - buttonText: { - color: "#fff", - fontSize: 16, - fontWeight: "600", - }, - secondaryButton: { - backgroundColor: "#e2e8f0", - paddingVertical: 12, - paddingHorizontal: 20, - borderRadius: 5, - alignItems: "center", - marginTop: 10, - }, - secondaryButtonText: { - color: "#4a5568", - fontSize: 16, - fontWeight: "600", - }, - footer: { - marginTop: 20, - alignItems: "center", - }, - footerText: { - color: "#666", - fontSize: 14, - }, - link: { - color: "#6366f1", - fontWeight: "bold", - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/upload.tsx b/examples/demos/ReactNativeDemo/app/upload.tsx deleted file mode 100644 index 6ddd853ea..000000000 --- a/examples/demos/ReactNativeDemo/app/upload.tsx +++ /dev/null @@ -1,552 +0,0 @@ -import type { FetchError } from "@nhost/nhost-js/fetch"; -import type { ErrorResponse, FileMetadata } from "@nhost/nhost-js/storage"; -import * as DocumentPicker from "expo-document-picker"; -import * as FileSystem from "expo-file-system"; -import { Stack } from "expo-router"; -import * as Sharing from "expo-sharing"; -import { useCallback, useEffect, useState } from "react"; -import { - ActivityIndicator, - Alert, - FlatList, - StyleSheet, - Text, - TouchableOpacity, - View, -} from "react-native"; -import ProtectedScreen from "./components/ProtectedScreen"; -import { useAuth } from "./lib/nhost/AuthProvider"; -import { blobToBase64, formatFileSize } from "./lib/utils"; - -interface DeleteStatus { - message: string; - isError: boolean; -} - -interface GraphqlGetFilesResponse { - files: FileMetadata[]; -} - -export default function Upload() { - const { nhost } = useAuth(); - const [selectedFile, setSelectedFile] = - useState(null); - const [uploading, setUploading] = useState(false); - const [uploadResult, setUploadResult] = useState(null); - const [isFetching, setIsFetching] = useState(true); - const [error, setError] = useState(null); - const [files, setFiles] = useState([]); - const [viewingFile, setViewingFile] = useState(null); - const [deleting, setDeleting] = useState(null); - const [deleteStatus, setDeleteStatus] = useState(null); - - const fetchFiles = useCallback(async () => { - setIsFetching(true); - setError(null); - - try { - // Fetch files using GraphQL query - const response = await nhost.graphql.request({ - query: `query GetFiles { - files { - id - name - size - mimeType - bucketId - uploadedByUserId - } - }`, - }); - - setFiles(response.body.data?.files || []); - } catch (err) { - const errMessage = - err instanceof Error ? err.message : "An unexpected error occurred"; - setError(`Failed to fetch files: ${errMessage}`); - } finally { - setIsFetching(false); - } - }, [nhost.graphql]); - - // Fetch existing files when component mounts - useEffect(() => { - void fetchFiles(); - }, [fetchFiles]); - - const pickDocument = async () => { - try { - const result = await DocumentPicker.getDocumentAsync({ - type: "*/*", // All file types - copyToCacheDirectory: true, - }); - - if (!result.canceled) { - setSelectedFile(result); - setError(null); - setUploadResult(null); - } - } catch (err) { - setError("Failed to pick document"); - console.error("DocumentPicker Error:", err); - } - }; - - const handleUpload = async () => { - if (!selectedFile || selectedFile.canceled) { - setError("Please select a file to upload"); - return; - } - - setUploading(true); - setError(null); - - try { - // For React Native, we need to read the file first - const fileToUpload = selectedFile.assets?.[0]; - if (!fileToUpload) { - throw new Error("No file selected"); - } - - const file: unknown = { - uri: fileToUpload.uri, - name: fileToUpload.name || "file", - type: fileToUpload.mimeType || "application/octet-stream", - }; - // Upload file using Nhost storage - const response = await nhost.storage.uploadFiles({ - "bucket-id": "default", - "file[]": [file as File], - }); - - // Get the processed file data - const uploadedFile = response.body.processedFiles?.[0]; - if (uploadedFile === undefined) { - throw new Error("Failed to upload file"); - } - - setUploadResult(uploadedFile); - - // Reset form - setSelectedFile(null); - - // Update files list - setFiles((prevFiles) => [uploadedFile, ...prevFiles]); - - // Refresh file list - await fetchFiles(); - - // Clear success message after 3 seconds - setTimeout(() => { - setUploadResult(null); - }, 3000); - } catch (err: unknown) { - const error = err as FetchError; - setError(`Failed to upload file: ${error.message}`); - console.error("Upload error:", err); - } finally { - setUploading(false); - } - }; - - // Function to handle viewing a file with proper authorization - const handleViewFile = async ( - fileId: string, - fileName: string, - mimeType: string, - ) => { - setViewingFile(fileId); - - try { - // Fetch the file with authentication using the SDK - const response = await nhost.storage.getFile(fileId); - - if (!response.body) { - throw new Error("Failed to retrieve file contents"); - } - - // For iOS/Android, we need to save the file to the device first - // Create a unique temp file path with a timestamp to prevent collisions - const fileExtension = fileName.includes(".") ? "" : ".file"; - const tempFileName = fileName.includes(".") - ? fileName - : `${fileName}${fileExtension}`; - const tempFilePath = `${FileSystem.cacheDirectory}${Date.now()}_${tempFileName}`; - - // Get the blob from the response - const blob = response.body; - - // Convert blob to base64 - const base64Data = await blobToBase64(blob); - - // Write the file to the filesystem - await FileSystem.writeAsStringAsync(tempFilePath, base64Data, { - encoding: FileSystem.EncodingType.Base64, - }); - - // Check if sharing is available (iOS & Android) - const isSharingAvailable = await Sharing.isAvailableAsync(); - - if (isSharingAvailable) { - // Open the file with the default app - await Sharing.shareAsync(tempFilePath, { - mimeType: mimeType || "application/octet-stream", - dialogTitle: `View ${fileName}`, - UTI: mimeType, // for iOS - }); - } else { - throw new Error("Sharing is not available on this device"); - } - } catch (err) { - const error = err as FetchError; - setError(`Failed to view file: ${error.message}`); - console.error("Error viewing file:", err); - Alert.alert("Error", `Failed to view file: ${error.message}`); - } finally { - setViewingFile(null); - } - }; - - // Function to handle deleting a file - const handleDeleteFile = (fileId: string) => { - if (!fileId || deleting) return; - - // Confirm deletion - Alert.alert("Delete File", "Are you sure you want to delete this file?", [ - { - text: "Cancel", - style: "cancel", - }, - { - text: "Delete", - style: "destructive", - onPress: () => { - void (async () => { - setDeleting(fileId); - setError(null); - setDeleteStatus(null); - - // Get the file name for the status message - const fileToDelete = files.find((file) => file.id === fileId); - const fileName = fileToDelete?.name || "File"; - - try { - // Delete the file using the Nhost storage SDK - await nhost.storage.deleteFile(fileId); - - // Show success message - setDeleteStatus({ - message: `${fileName} deleted successfully`, - isError: false, - }); - - // Update the local files list by removing the deleted file - setFiles(files.filter((file) => file.id !== fileId)); - - // Refresh the file list - await fetchFiles(); - - // Clear the success message after 3 seconds - setTimeout(() => { - setDeleteStatus(null); - }, 3000); - } catch (err) { - // Show error message - const error = err as FetchError; - setDeleteStatus({ - message: `Failed to delete ${fileName}: ${error.message}`, - isError: true, - }); - console.error("Error deleting file:", err); - } finally { - setDeleting(null); - } - })(); - }, - }, - ]); - }; - - return ( - - - - {/* Upload Form */} - - Upload a File - - - - ⬆️ - - Tap to select a file - {selectedFile && - !selectedFile.canceled && - selectedFile.assets?.[0] && ( - - {selectedFile.assets[0].name}( - {formatFileSize(selectedFile.assets[0].size || 0)}) - - )} - - - {error && ( - - {error} - - )} - - {uploadResult && ( - - - File uploaded successfully! - - - )} - - - - {uploading ? "Uploading..." : "Upload File"} - - - - - {/* Files List */} - - Your Files - - {deleteStatus && ( - - - {deleteStatus.message} - - - )} - - {isFetching ? ( - - - Loading files... - - ) : files.length === 0 ? ( - No files uploaded yet. - ) : ( - item.id || Math.random().toString()} - renderItem={({ item }) => ( - - - - {item.name} - - - {item.mimeType} • {formatFileSize(item.size || 0)} - - - - - handleViewFile( - item.id || "unknown", - item.name || "unknown", - item.mimeType || "unknown", - ) - } - disabled={viewingFile === item.id} - > - {viewingFile === item.id ? ( - - ) : ( - 👁️ - )} - - handleDeleteFile(item.id || "unknown")} - disabled={deleting === item.id} - > - {deleting === item.id ? ( - - ) : ( - 🗑️ - )} - - - - )} - style={styles.fileList} - /> - )} - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - padding: 16, - backgroundColor: "#f5f5f5", - }, - card: { - backgroundColor: "#fff", - borderRadius: 10, - padding: 20, - marginBottom: 20, - shadowColor: "#000", - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 3, - }, - title: { - fontSize: 20, - fontWeight: "bold", - marginBottom: 16, - color: "#333", - }, - fileUpload: { - borderWidth: 2, - borderColor: "#ddd", - borderStyle: "dashed", - borderRadius: 10, - padding: 20, - alignItems: "center", - justifyContent: "center", - backgroundColor: "#f9f9f9", - marginBottom: 16, - }, - uploadIcon: { - marginBottom: 10, - }, - uploadIconText: { - fontSize: 24, - }, - uploadText: { - fontSize: 16, - color: "#666", - }, - fileName: { - marginTop: 8, - color: "#0066cc", - fontSize: 14, - }, - button: { - backgroundColor: "#0066cc", - padding: 15, - borderRadius: 8, - alignItems: "center", - }, - buttonDisabled: { - backgroundColor: "#ccc", - }, - buttonText: { - color: "white", - fontWeight: "bold", - fontSize: 16, - }, - errorContainer: { - backgroundColor: "#ffebee", - padding: 10, - borderRadius: 8, - marginBottom: 16, - borderLeftWidth: 4, - borderLeftColor: "#f44336", - }, - errorText: { - color: "#d32f2f", - }, - successContainer: { - backgroundColor: "#e8f5e9", - padding: 10, - borderRadius: 8, - marginBottom: 16, - borderLeftWidth: 4, - borderLeftColor: "#4caf50", - }, - successText: { - color: "#2e7d32", - }, - statusContainer: { - padding: 10, - borderRadius: 8, - marginBottom: 16, - borderLeftWidth: 4, - }, - loadingContainer: { - alignItems: "center", - padding: 20, - }, - loadingText: { - marginTop: 10, - color: "#666", - }, - emptyText: { - textAlign: "center", - color: "#666", - padding: 20, - }, - fileList: { - maxHeight: 300, - }, - fileItem: { - flexDirection: "row", - justifyContent: "space-between", - alignItems: "center", - paddingVertical: 12, - paddingHorizontal: 8, - borderBottomWidth: 1, - borderBottomColor: "#eee", - }, - fileInfo: { - flex: 1, - paddingRight: 10, - }, - fileNameText: { - fontSize: 16, - fontWeight: "500", - color: "#333", - marginBottom: 4, - }, - fileDetails: { - fontSize: 12, - color: "#777", - }, - fileActions: { - flexDirection: "row", - }, - actionButton: { - padding: 8, - marginHorizontal: 4, - borderRadius: 20, - backgroundColor: "#f0f0f0", - }, - deleteButton: { - backgroundColor: "#fff0f0", - }, - actionText: { - fontSize: 16, - }, -}); diff --git a/examples/demos/ReactNativeDemo/app/verify.tsx b/examples/demos/ReactNativeDemo/app/verify.tsx deleted file mode 100644 index f563bed4d..000000000 --- a/examples/demos/ReactNativeDemo/app/verify.tsx +++ /dev/null @@ -1,265 +0,0 @@ -import { router, useLocalSearchParams } from "expo-router"; -import { useEffect, useState } from "react"; -import { - ActivityIndicator, - StyleSheet, - Text, - TouchableOpacity, - View, -} from "react-native"; -import { useAuth } from "./lib/nhost/AuthProvider"; - -export default function Verify() { - const params = useLocalSearchParams<{ refreshToken: string }>(); - const [status, setStatus] = useState<"verifying" | "success" | "error">( - "verifying", - ); - const [error, setError] = useState(""); - - const { nhost, isAuthenticated } = useAuth(); - - useEffect(() => { - const refreshToken = params.refreshToken; - - if (!refreshToken) { - setStatus("error"); - setError("No refresh token found in the link"); - return; - } - - // Flag to handle component unmounting during async operations - let isMounted = true; - - async function processToken(): Promise { - try { - // First display the verifying message for at least a moment - await new Promise((resolve) => setTimeout(resolve, 500)); - - if (!isMounted) return; - - if (!refreshToken) { - // Collect all URL parameters to display - const allParams: Record = {}; - Object.entries(params).forEach(([key, value]) => { - if (typeof value === "string") { - allParams[key] = value; - } - }); - - setStatus("error"); - setError("No refresh token found in the link"); - return; - } - - // Process the token - await nhost.auth.refreshToken({ refreshToken }); - - if (!isMounted) return; - - setStatus("success"); - - // Wait to show success message briefly, then redirect - setTimeout(() => { - if (isMounted) router.replace("/profile"); - }, 1500); - } catch (err) { - if (!isMounted) return; - - const errMessage = - err instanceof Error ? err.message : "An unexpected error occurred"; - - setStatus("error"); - setError(`An error occurred during verification: ${errMessage}`); - } - } - - void processToken(); - - // Cleanup function - return () => { - isMounted = false; - }; - }, [params, nhost.auth]); - - // If already authenticated and not handling verification, redirect to profile - useEffect(() => { - if (isAuthenticated && status !== "verifying") { - router.replace("/profile"); - } - }, [isAuthenticated, status]); - - return ( - - Nhost SDK Demo - - - Email Verification - - - {status === "verifying" && ( - - Verifying your email... - - - )} - - {status === "success" && ( - - ✓ Successfully verified! - - You'll be redirected to your profile page shortly... - - - )} - - {status === "error" && ( - - Verification failed - {error} - - - Testing in Expo Go? - - Make sure your magic link uses the proper Expo Go format. - - - - router.replace("/signin")} - style={styles.button} - > - Back to Sign In - - - )} - - - - ); -} - -const styles = StyleSheet.create({ - debugInfo: { - backgroundColor: "#fff8dc", - padding: 10, - borderRadius: 5, - marginVertical: 10, - borderWidth: 1, - borderColor: "#ffd700", - }, - debugTitle: { - fontWeight: "bold", - marginBottom: 5, - color: "#b8860b", - }, - debugText: { - color: "#5a4a00", - fontSize: 14, - }, - container: { - flex: 1, - backgroundColor: "#f5f5f5", - justifyContent: "center", - padding: 20, - }, - title: { - fontSize: 24, - fontWeight: "bold", - textAlign: "center", - marginBottom: 20, - color: "#333", - }, - card: { - width: "100%", - maxWidth: 400, - backgroundColor: "#fff", - borderRadius: 10, - padding: 20, - alignSelf: "center", - shadowColor: "#000", - shadowOffset: { - width: 0, - height: 2, - }, - shadowOpacity: 0.1, - shadowRadius: 3.84, - elevation: 5, - }, - cardTitle: { - fontSize: 20, - fontWeight: "bold", - marginBottom: 20, - textAlign: "center", - }, - contentContainer: { - alignItems: "center", - paddingVertical: 20, - }, - statusText: { - fontSize: 16, - textAlign: "center", - marginBottom: 15, - color: "#4a5568", - }, - spinner: { - marginVertical: 20, - }, - successText: { - color: "#38a169", - fontSize: 18, - fontWeight: "bold", - textAlign: "center", - marginBottom: 10, - }, - errorText: { - color: "#e53e3e", - fontSize: 18, - fontWeight: "bold", - textAlign: "center", - marginBottom: 10, - }, - paramsContainer: { - backgroundColor: "#f7fafc", - borderRadius: 5, - padding: 10, - marginVertical: 15, - width: "100%", - maxHeight: 150, - }, - paramsTitle: { - fontWeight: "bold", - marginBottom: 5, - color: "#2d3748", - }, - paramRow: { - flexDirection: "row", - marginBottom: 5, - }, - paramKey: { - color: "#4299e1", - marginRight: 5, - fontFamily: "monospace", - }, - paramValue: { - flex: 1, - fontFamily: "monospace", - color: "#2d3748", - }, - button: { - backgroundColor: "#6366f1", - paddingVertical: 12, - borderRadius: 5, - alignItems: "center", - marginTop: 15, - width: "100%", - }, - buttonText: { - color: "#fff", - fontSize: 16, - fontWeight: "600", - }, -}); diff --git a/examples/demos/ReactNativeDemo/assets/images/adaptive-icon.png b/examples/demos/ReactNativeDemo/assets/images/adaptive-icon.png deleted file mode 100644 index 03d6f6b6c..000000000 Binary files a/examples/demos/ReactNativeDemo/assets/images/adaptive-icon.png and /dev/null differ diff --git a/examples/demos/ReactNativeDemo/assets/images/splash-icon.png b/examples/demos/ReactNativeDemo/assets/images/splash-icon.png deleted file mode 100644 index 03d6f6b6c..000000000 Binary files a/examples/demos/ReactNativeDemo/assets/images/splash-icon.png and /dev/null differ diff --git a/examples/demos/ReactNativeDemo/package.json b/examples/demos/ReactNativeDemo/package.json deleted file mode 100644 index 52769d77b..000000000 --- a/examples/demos/ReactNativeDemo/package.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "reactnativewebdemo", - "main": "expo-router/entry", - "version": "1.0.0", - "type": "module", - "scripts": { - "start": "expo start", - "reset-project": "node ./scripts/reset-project.js", - "generate": "echo 'Nothing to do'", - "test": "pnpm test:typecheck && pnpm test:lint", - "test:typecheck": "tsc --noEmit", - "test:lint": "biome check", - "format": "biome format --write", - "build": "pnpm expo export -p ios -p android", - "android": "expo start --android", - "ios": "expo start --ios" - }, - "dependencies": { - "@expo/vector-icons": "^14.1.0", - "@nhost/nhost-js": "workspace:*", - "@react-native-async-storage/async-storage": "^2.1.2", - "@react-navigation/bottom-tabs": "^7.3.14", - "@react-navigation/elements": "^2.4.3", - "@react-navigation/native": "^7.1.10", - "expo": "~53.0.10", - "expo-apple-authentication": "~7.2.4", - "expo-blur": "~14.1.5", - "expo-clipboard": "^7.1.4", - "expo-constants": "~17.1.6", - "expo-crypto": "~14.1.4", - "expo-document-picker": "^13.1.5", - "expo-file-system": "^18.1.10", - "expo-font": "~13.3.1", - "expo-haptics": "~14.1.4", - "expo-image": "~2.2.0", - "expo-linking": "~7.1.5", - "expo-router": "~5.0.7", - "expo-sharing": "^13.1.5", - "expo-splash-screen": "~0.30.9", - "expo-status-bar": "~2.2.3", - "expo-symbols": "~0.4.5", - "expo-system-ui": "~5.0.8", - "expo-web-browser": "~14.1.6", - "react": "19.0.0", - "react-native": "0.79.3", - "react-native-gesture-handler": "~2.24.0", - "react-native-reanimated": "~3.17.5", - "react-native-safe-area-context": "5.4.0", - "react-native-screens": "^4.11.1", - "react-native-webview": "13.13.5" - }, - "devDependencies": { - "@babel/core": "^7.27.4", - "@types/react": "~19.0.14", - "@types/node": "^22.15.17" - }, - "private": true, - "pnpm": { - "overrides": { - "js-yaml@<=4.1.0": ">=4.1.1", - "glob@>=10.3.7 <=11.0.3": ">=11.1.0" - } - } -} diff --git a/examples/demos/ReactNativeDemo/pnpm-lock.yaml b/examples/demos/ReactNativeDemo/pnpm-lock.yaml deleted file mode 100644 index db9a8bc83..000000000 --- a/examples/demos/ReactNativeDemo/pnpm-lock.yaml +++ /dev/null @@ -1,6275 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -overrides: - js-yaml@<=4.1.0: '>=4.1.1' - glob@>=10.3.7 <=11.0.3: '>=11.1.0' - -importers: - - .: - dependencies: - '@expo/vector-icons': - specifier: ^14.1.0 - version: 14.1.0(expo-font@13.3.2(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - '@nhost/nhost-js': - specifier: workspace:* - version: link:../../../packages/nhost-js - '@react-native-async-storage/async-storage': - specifier: ^2.1.2 - version: 2.2.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - '@react-navigation/bottom-tabs': - specifier: ^7.3.14 - version: 7.4.7(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-screens@4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - '@react-navigation/elements': - specifier: ^2.4.3 - version: 2.6.4(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - '@react-navigation/native': - specifier: ^7.1.10 - version: 7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo: - specifier: ~53.0.10 - version: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-apple-authentication: - specifier: ~7.2.4 - version: 7.2.4(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - expo-blur: - specifier: ~14.1.5 - version: 14.1.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-clipboard: - specifier: ^7.1.4 - version: 7.1.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-constants: - specifier: ~17.1.6 - version: 17.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - expo-crypto: - specifier: ~14.1.4 - version: 14.1.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)) - expo-document-picker: - specifier: ^13.1.5 - version: 13.1.6(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)) - expo-file-system: - specifier: ^18.1.10 - version: 18.1.11(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - expo-font: - specifier: ~13.3.1 - version: 13.3.2(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0) - expo-haptics: - specifier: ~14.1.4 - version: 14.1.4(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)) - expo-image: - specifier: ~2.2.0 - version: 2.2.1(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-linking: - specifier: ~7.1.5 - version: 7.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-router: - specifier: ~5.0.7 - version: 5.0.7(6ef5553abe53fc2c54fd463e8e887e39) - expo-sharing: - specifier: ^13.1.5 - version: 13.1.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)) - expo-splash-screen: - specifier: ~0.30.9 - version: 0.30.10(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)) - expo-status-bar: - specifier: ~2.2.3 - version: 2.2.3(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-symbols: - specifier: ~0.4.5 - version: 0.4.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - expo-system-ui: - specifier: ~5.0.8 - version: 5.0.10(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - expo-web-browser: - specifier: ~14.1.6 - version: 14.1.6(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - react: - specifier: 19.0.0 - version: 19.0.0 - react-native: - specifier: 0.79.3 - version: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - react-native-gesture-handler: - specifier: ~2.24.0 - version: 2.24.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-reanimated: - specifier: ~3.17.5 - version: 3.17.5(@babel/core@7.28.3)(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-safe-area-context: - specifier: 5.4.0 - version: 5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-screens: - specifier: ^4.11.1 - version: 4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-webview: - specifier: 13.13.5 - version: 13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - devDependencies: - '@babel/core': - specifier: ^7.27.4 - version: 7.28.3 - '@types/node': - specifier: ^22.15.17 - version: 22.18.1 - '@types/react': - specifier: ~19.0.14 - version: 19.0.14 - -packages: - - '@0no-co/graphql.web@1.2.0': - resolution: {integrity: sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==} - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - peerDependenciesMeta: - graphql: - optional: true - - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - - '@babel/code-frame@7.10.4': - resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.28.0': - resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.28.3': - resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-create-class-features-plugin@7.28.3': - resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-create-regexp-features-plugin@7.27.1': - resolution: {integrity: sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-define-polyfill-provider@0.6.5': - resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-remap-async-to-generator@7.27.1': - resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-wrap-function@7.28.3': - resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.3': - resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==} - engines: {node: '>=6.9.0'} - - '@babel/highlight@7.25.9': - resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.28.3': - resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-proposal-decorators@7.28.0': - resolution: {integrity: sha512-zOiZqvANjWDUaUS9xMxbMcK/Zccztbe/6ikvUXaG9nsPH3w6qh5UaPGAnirI/WhIbZ8m3OHU0ReyPrknG+ZKeg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-export-default-from@7.27.1': - resolution: {integrity: sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-async-generators@7.8.4': - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-bigint@7.8.3': - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-class-properties@7.12.13': - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-class-static-block@7.14.5': - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-decorators@7.27.1': - resolution: {integrity: sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-dynamic-import@7.8.3': - resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-export-default-from@7.27.1': - resolution: {integrity: sha512-eBC/3KSekshx19+N40MzjWqJd7KTEdOoLesAfa4IDFI8eRz5a47i5Oszus6zG/cwIXN63YhgLOMSSNJx49sENg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-flow@7.27.1': - resolution: {integrity: sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-import-meta@7.10.4': - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-json-strings@7.8.3': - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-logical-assignment-operators@7.10.4': - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-numeric-separator@7.10.4': - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-object-rest-spread@7.8.3': - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-catch-binding@7.8.3': - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-chaining@7.8.3': - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-private-property-in-object@7.14.5': - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-top-level-await@7.14.5': - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-async-generator-functions@7.28.0': - resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-async-to-generator@7.27.1': - resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-block-scoping@7.28.0': - resolution: {integrity: sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-class-properties@7.27.1': - resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-classes@7.28.3': - resolution: {integrity: sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-computed-properties@7.27.1': - resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-destructuring@7.28.0': - resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-export-namespace-from@7.27.1': - resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-flow-strip-types@7.27.1': - resolution: {integrity: sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-for-of@7.27.1': - resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-function-name@7.27.1': - resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-literals@7.27.1': - resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-logical-assignment-operators@7.27.1': - resolution: {integrity: sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': - resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-numeric-separator@7.27.1': - resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-object-rest-spread@7.28.0': - resolution: {integrity: sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-catch-binding@7.27.1': - resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-chaining@7.27.1': - resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-parameters@7.27.7': - resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-methods@7.27.1': - resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-property-in-object@7.27.1': - resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-display-name@7.28.0': - resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-development@7.27.1': - resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx@7.27.1': - resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-pure-annotations@7.27.1': - resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-regenerator@7.28.3': - resolution: {integrity: sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-runtime@7.28.3': - resolution: {integrity: sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-shorthand-properties@7.27.1': - resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-spread@7.27.1': - resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-sticky-regex@7.27.1': - resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-template-literals@7.27.1': - resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typescript@7.28.0': - resolution: {integrity: sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-regex@7.27.1': - resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-react@7.27.1': - resolution: {integrity: sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-typescript@7.27.1': - resolution: {integrity: sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.28.3': - resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.3': - resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.2': - resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} - engines: {node: '>=6.9.0'} - - '@egjs/hammerjs@2.0.17': - resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} - engines: {node: '>=0.8.0'} - - '@expo/cli@0.24.21': - resolution: {integrity: sha512-DT6K9vgFHqqWL/19mU1ofRcPoO1pn4qmgi76GtuiNU4tbBe/02mRHwFsQw7qRfFAT28If5e/wiwVozgSuZVL8g==} - hasBin: true - - '@expo/code-signing-certificates@0.0.5': - resolution: {integrity: sha512-BNhXkY1bblxKZpltzAx98G2Egj9g1Q+JRcvR7E99DOj862FTCX+ZPsAUtPTr7aHxwtrL7+fL3r0JSmM9kBm+Bw==} - - '@expo/config-plugins@10.1.2': - resolution: {integrity: sha512-IMYCxBOcnuFStuK0Ay+FzEIBKrwW8OVUMc65+v0+i7YFIIe8aL342l7T4F8lR4oCfhXn7d6M5QPgXvjtc/gAcw==} - - '@expo/config-types@53.0.5': - resolution: {integrity: sha512-kqZ0w44E+HEGBjy+Lpyn0BVL5UANg/tmNixxaRMLS6nf37YsDrLk2VMAmeKMMk5CKG0NmOdVv3ngeUjRQMsy9g==} - - '@expo/config@11.0.13': - resolution: {integrity: sha512-TnGb4u/zUZetpav9sx/3fWK71oCPaOjZHoVED9NaEncktAd0Eonhq5NUghiJmkUGt3gGSjRAEBXiBbbY9/B1LA==} - - '@expo/devcert@1.2.0': - resolution: {integrity: sha512-Uilcv3xGELD5t/b0eM4cxBFEKQRIivB3v7i+VhWLV/gL98aw810unLKKJbGAxAIhY6Ipyz8ChWibFsKFXYwstA==} - - '@expo/env@1.0.7': - resolution: {integrity: sha512-qSTEnwvuYJ3umapO9XJtrb1fAqiPlmUUg78N0IZXXGwQRt+bkp0OBls+Y5Mxw/Owj8waAM0Z3huKKskRADR5ow==} - - '@expo/fingerprint@0.13.4': - resolution: {integrity: sha512-MYfPYBTMfrrNr07DALuLhG6EaLVNVrY/PXjEzsjWdWE4ZFn0yqI0IdHNkJG7t1gePT8iztHc7qnsx+oo/rDo6w==} - hasBin: true - - '@expo/image-utils@0.7.6': - resolution: {integrity: sha512-GKnMqC79+mo/1AFrmAcUcGfbsXXTRqOMNS1umebuevl3aaw+ztsYEFEiuNhHZW7PQ3Xs3URNT513ZxKhznDscw==} - - '@expo/json-file@9.1.5': - resolution: {integrity: sha512-prWBhLUlmcQtvN6Y7BpW2k9zXGd3ySa3R6rAguMJkp1z22nunLN64KYTUWfijFlprFoxm9r2VNnGkcbndAlgKA==} - - '@expo/metro-config@0.20.17': - resolution: {integrity: sha512-lpntF2UZn5bTwrPK6guUv00Xv3X9mkN3YYla+IhEHiYXWyG7WKOtDU0U4KR8h3ubkZ6SPH3snDyRyAzMsWtZFA==} - - '@expo/metro-runtime@5.0.4': - resolution: {integrity: sha512-r694MeO+7Vi8IwOsDIDzH/Q5RPMt1kUDYbiTJwnO15nIqiDwlE8HU55UlRhffKZy6s5FmxQsZ8HA+T8DqUW8cQ==} - peerDependencies: - react-native: '*' - - '@expo/osascript@2.2.5': - resolution: {integrity: sha512-Bpp/n5rZ0UmpBOnl7Li3LtM7la0AR3H9NNesqL+ytW5UiqV/TbonYW3rDZY38u4u/lG7TnYflVIVQPD+iqZJ5w==} - engines: {node: '>=12'} - - '@expo/package-manager@1.8.6': - resolution: {integrity: sha512-gcdICLuL+nHKZagPIDC5tX8UoDDB8vNA5/+SaQEqz8D+T2C4KrEJc2Vi1gPAlDnKif834QS6YluHWyxjk0yZlQ==} - - '@expo/plist@0.3.5': - resolution: {integrity: sha512-9RYVU1iGyCJ7vWfg3e7c/NVyMFs8wbl+dMWZphtFtsqyN9zppGREU3ctlD3i8KUE0sCUTVnLjCWr+VeUIDep2g==} - - '@expo/prebuild-config@9.0.11': - resolution: {integrity: sha512-0DsxhhixRbCCvmYskBTq8czsU0YOBsntYURhWPNpkl0IPVpeP9haE5W4OwtHGzXEbmHdzaoDwNmVcWjS/mqbDw==} - - '@expo/schema-utils@0.1.0': - resolution: {integrity: sha512-Me2avOfbcVT/O5iRmPKLCCSvbCfVfxIstGMlzVJOffplaZX1+ut8D18siR1wx5fkLMTWKs14ozEz11cGUY7hcw==} - - '@expo/sdk-runtime-versions@1.0.0': - resolution: {integrity: sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==} - - '@expo/server@0.6.3': - resolution: {integrity: sha512-Ea7NJn9Xk1fe4YeJ86rObHSv/bm3u/6WiQPXEqXJ2GrfYpVab2Swoh9/PnSM3KjR64JAgKjArDn1HiPjITCfHA==} - - '@expo/spawn-async@1.7.2': - resolution: {integrity: sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==} - engines: {node: '>=12'} - - '@expo/sudo-prompt@9.3.2': - resolution: {integrity: sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==} - - '@expo/vector-icons@14.1.0': - resolution: {integrity: sha512-7T09UE9h8QDTsUeMGymB4i+iqvtEeaO5VvUjryFB4tugDTG/bkzViWA74hm5pfjjDEhYMXWaX112mcvhccmIwQ==} - peerDependencies: - expo-font: '*' - react: '*' - react-native: '*' - - '@expo/ws-tunnel@1.0.6': - resolution: {integrity: sha512-nDRbLmSrJar7abvUjp3smDwH8HcbZcoOEa5jVPUv9/9CajgmWw20JNRwTuBRzWIWIkEJDkz20GoNA+tSwUqk0Q==} - - '@expo/xcpretty@4.3.2': - resolution: {integrity: sha512-ReZxZ8pdnoI3tP/dNnJdnmAk7uLT4FjsKDGW7YeDdvdOMz2XCQSmSCM9IWlrXuWtMF9zeSB6WJtEhCQ41gQOfw==} - hasBin: true - - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@isaacs/fs-minipass@4.0.1': - resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} - engines: {node: '>=18.0.0'} - - '@isaacs/ttlcache@1.4.1': - resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} - engines: {node: '>=12'} - - '@istanbuljs/load-nyc-config@1.1.0': - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - - '@jest/create-cache-key-function@29.7.0': - resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/environment@29.7.0': - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/fake-timers@29.7.0': - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/transform@29.7.0': - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/types@29.6.3': - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/source-map@0.3.11': - resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.30': - resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-slot@1.2.0': - resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@react-native-async-storage/async-storage@2.2.0': - resolution: {integrity: sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==} - peerDependencies: - react-native: ^0.0.0-0 || >=0.65 <1.0 - - '@react-native/assets-registry@0.79.3': - resolution: {integrity: sha512-Vy8DQXCJ21YSAiHxrNBz35VqVlZPpRYm50xRTWRf660JwHuJkFQG8cUkrLzm7AUriqUXxwpkQHcY+b0ibw9ejQ==} - engines: {node: '>=18'} - - '@react-native/babel-plugin-codegen@0.79.6': - resolution: {integrity: sha512-CS5OrgcMPixOyUJ/Sk/HSsKsKgyKT5P7y3CojimOQzWqRZBmoQfxdST4ugj7n1H+ebM2IKqbgovApFbqXsoX0g==} - engines: {node: '>=18'} - - '@react-native/babel-preset@0.79.6': - resolution: {integrity: sha512-H+FRO+r2Ql6b5IwfE0E7D52JhkxjeGSBSUpCXAI5zQ60zSBJ54Hwh2bBJOohXWl4J+C7gKYSAd2JHMUETu+c/A==} - engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' - - '@react-native/codegen@0.79.3': - resolution: {integrity: sha512-CZejXqKch/a5/s/MO5T8mkAgvzCXgsTkQtpCF15kWR9HN8T+16k0CsN7TXAxXycltoxiE3XRglOrZNEa/TiZUQ==} - engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' - - '@react-native/codegen@0.79.6': - resolution: {integrity: sha512-iRBX8Lgbqypwnfba7s6opeUwVyaR23mowh9ILw7EcT2oLz3RqMmjJdrbVpWhGSMGq2qkPfqAH7bhO8C7O+xfjQ==} - engines: {node: '>=18'} - peerDependencies: - '@babel/core': '*' - - '@react-native/community-cli-plugin@0.79.3': - resolution: {integrity: sha512-N/+p4HQqN4yK6IRzn7OgMvUIcrmEWkecglk1q5nj+AzNpfIOzB+mqR20SYmnPfeXF+mZzYCzRANb3KiM+WsSDA==} - engines: {node: '>=18'} - peerDependencies: - '@react-native-community/cli': '*' - peerDependenciesMeta: - '@react-native-community/cli': - optional: true - - '@react-native/debugger-frontend@0.79.3': - resolution: {integrity: sha512-ImNDuEeKH6lEsLXms3ZsgIrNF94jymfuhPcVY5L0trzaYNo9ZFE9Ni2/18E1IbfXxdeIHrCSBJlWD6CTm7wu5A==} - engines: {node: '>=18'} - - '@react-native/debugger-frontend@0.79.6': - resolution: {integrity: sha512-lIK/KkaH7ueM22bLO0YNaQwZbT/oeqhaghOvmZacaNVbJR1Cdh/XAqjT8FgCS+7PUnbxA8B55NYNKGZG3O2pYw==} - engines: {node: '>=18'} - - '@react-native/dev-middleware@0.79.3': - resolution: {integrity: sha512-x88+RGOyG71+idQefnQg7wLhzjn/Scs+re1O5vqCkTVzRAc/f7SdHMlbmECUxJPd08FqMcOJr7/X3nsJBrNuuw==} - engines: {node: '>=18'} - - '@react-native/dev-middleware@0.79.6': - resolution: {integrity: sha512-BK3GZBa9c7XSNR27EDRtxrgyyA3/mf1j3/y+mPk7Ac0Myu85YNrXnC9g3mL5Ytwo0g58TKrAIgs1fF2Q5Mn6mQ==} - engines: {node: '>=18'} - - '@react-native/gradle-plugin@0.79.3': - resolution: {integrity: sha512-imfpZLhNBc9UFSzb/MOy2tNcIBHqVmexh/qdzw83F75BmUtLb/Gs1L2V5gw+WI1r7RqDILbWk7gXB8zUllwd+g==} - engines: {node: '>=18'} - - '@react-native/js-polyfills@0.79.3': - resolution: {integrity: sha512-PEBtg6Kox6KahjCAch0UrqCAmHiNLEbp2SblUEoFAQnov4DSxBN9safh+QSVaCiMAwLjvNfXrJyygZz60Dqz3Q==} - engines: {node: '>=18'} - - '@react-native/normalize-colors@0.79.3': - resolution: {integrity: sha512-T75NIQPRFCj6DFMxtcVMJTZR+3vHXaUMSd15t+CkJpc5LnyX91GVaPxpRSAdjFh7m3Yppl5MpdjV/fntImheYQ==} - - '@react-native/normalize-colors@0.79.5': - resolution: {integrity: sha512-nGXMNMclZgzLUxijQQ38Dm3IAEhgxuySAWQHnljFtfB0JdaMwpe0Ox9H7Tp2OgrEA+EMEv+Od9ElKlHwGKmmvQ==} - - '@react-native/virtualized-lists@0.79.3': - resolution: {integrity: sha512-/0rRozkn+iIHya2vnnvprDgT7QkfI54FLrACAN3BLP7MRlfOIGOrZsXpRLndnLBVnjNzkcre84i1RecjoXnwIA==} - engines: {node: '>=18'} - peerDependencies: - '@types/react': ^19.0.0 - react: '*' - react-native: '*' - peerDependenciesMeta: - '@types/react': - optional: true - - '@react-navigation/bottom-tabs@7.4.7': - resolution: {integrity: sha512-SQ4KuYV9yr3SV/thefpLWhAD0CU2CrBMG1l0w/QKl3GYuGWdN5OQmdQdmaPZGtsjjVOb+N9Qo7Tf6210P4TlpA==} - peerDependencies: - '@react-navigation/native': ^7.1.17 - react: '>= 18.2.0' - react-native: '*' - react-native-safe-area-context: '>= 4.0.0' - react-native-screens: '>= 4.0.0' - - '@react-navigation/core@7.12.4': - resolution: {integrity: sha512-xLFho76FA7v500XID5z/8YfGTvjQPw7/fXsq4BIrVSqetNe/o/v+KAocEw4ots6kyv3XvSTyiWKh2g3pN6xZ9Q==} - peerDependencies: - react: '>= 18.2.0' - - '@react-navigation/elements@2.6.4': - resolution: {integrity: sha512-O3X9vWXOEhAO56zkQS7KaDzL8BvjlwZ0LGSteKpt1/k6w6HONG+2Wkblrb057iKmehTkEkQMzMLkXiuLmN5x9Q==} - peerDependencies: - '@react-native-masked-view/masked-view': '>= 0.2.0' - '@react-navigation/native': ^7.1.17 - react: '>= 18.2.0' - react-native: '*' - react-native-safe-area-context: '>= 4.0.0' - peerDependenciesMeta: - '@react-native-masked-view/masked-view': - optional: true - - '@react-navigation/native-stack@7.3.26': - resolution: {integrity: sha512-EjaBWzLZ76HJGOOcWCFf+h/M+Zg7M1RalYioDOb6ZdXHz7AwYNidruT3OUAQgSzg3gVLqvu5OYO0jFsNDPCZxQ==} - peerDependencies: - '@react-navigation/native': ^7.1.17 - react: '>= 18.2.0' - react-native: '*' - react-native-safe-area-context: '>= 4.0.0' - react-native-screens: '>= 4.0.0' - - '@react-navigation/native@7.1.17': - resolution: {integrity: sha512-uEcYWi1NV+2Qe1oELfp9b5hTYekqWATv2cuwcOAg5EvsIsUPtzFrKIasgUXLBRGb9P7yR5ifoJ+ug4u6jdqSTQ==} - peerDependencies: - react: '>= 18.2.0' - react-native: '*' - - '@react-navigation/routers@7.5.1': - resolution: {integrity: sha512-pxipMW/iEBSUrjxz2cDD7fNwkqR4xoi0E/PcfTQGCcdJwLoaxzab5kSadBLj1MTJyT0YRrOXL9umHpXtp+Dv4w==} - - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@sinonjs/commons@3.0.1': - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - - '@sinonjs/fake-timers@10.3.0': - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/graceful-fs@4.1.9': - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - - '@types/hammerjs@2.0.46': - resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==} - - '@types/istanbul-lib-coverage@2.0.6': - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - - '@types/istanbul-lib-report@3.0.3': - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - - '@types/istanbul-reports@3.0.4': - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/node@22.18.1': - resolution: {integrity: sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==} - - '@types/react@19.0.14': - resolution: {integrity: sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw==} - - '@types/stack-utils@2.0.3': - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@17.0.33': - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - - '@urql/core@5.2.0': - resolution: {integrity: sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==} - - '@urql/exchange-retry@1.3.2': - resolution: {integrity: sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg==} - peerDependencies: - '@urql/core': ^5.0.0 - - '@xmldom/xmldom@0.8.11': - resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} - engines: {node: '>=10.0.0'} - - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - - ajv-keywords@5.1.0: - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 - - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - - anser@1.4.10: - resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} - - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - - ansi-regex@4.1.1: - resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} - engines: {node: '>=6'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.0: - resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} - engines: {node: '>=12'} - - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - - async-limiter@1.0.1: - resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} - - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - babel-plugin-polyfill-corejs2@0.4.14: - resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - babel-plugin-polyfill-corejs3@0.13.0: - resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - babel-plugin-polyfill-regenerator@0.6.5: - resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - babel-plugin-react-native-web@0.19.13: - resolution: {integrity: sha512-4hHoto6xaN23LCyZgL9LJZc3olmAxd7b6jDzlZnKXAh4rRAbZRKNBJoOOdp46OBqgy+K0t0guTj5/mhA8inymQ==} - - babel-plugin-syntax-hermes-parser@0.25.1: - resolution: {integrity: sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ==} - - babel-plugin-transform-flow-enums@0.0.2: - resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} - - babel-preset-current-node-syntax@1.2.0: - resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} - peerDependencies: - '@babel/core': ^7.0.0 || ^8.0.0-0 - - babel-preset-expo@13.2.4: - resolution: {integrity: sha512-3IKORo3KR+4qtLdCkZNDj8KeA43oBn7RRQejFGWfiZgu/NeaRUSri8YwYjZqybm7hn3nmMv9OLahlvXBX23o5Q==} - peerDependencies: - babel-plugin-react-compiler: ^19.0.0-beta-e993439-20250405 - peerDependenciesMeta: - babel-plugin-react-compiler: - optional: true - - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - better-opn@3.0.2: - resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} - engines: {node: '>=12.0.0'} - - big-integer@1.6.52: - resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} - engines: {node: '>=0.6'} - - bplist-creator@0.1.0: - resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} - - bplist-parser@0.3.1: - resolution: {integrity: sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==} - engines: {node: '>= 5.10.0'} - - bplist-parser@0.3.2: - resolution: {integrity: sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==} - engines: {node: '>= 5.10.0'} - - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.25.4: - resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - caller-callsite@2.0.0: - resolution: {integrity: sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==} - engines: {node: '>=4'} - - caller-path@2.0.0: - resolution: {integrity: sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==} - engines: {node: '>=4'} - - callsites@2.0.0: - resolution: {integrity: sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==} - engines: {node: '>=4'} - - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - - caniuse-lite@1.0.30001739: - resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==} - - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chownr@3.0.0: - resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} - engines: {node: '>=18'} - - chrome-launcher@0.15.2: - resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} - engines: {node: '>=12.13.0'} - hasBin: true - - chromium-edge-launcher@0.2.0: - resolution: {integrity: sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==} - - ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - cli-cursor@2.1.0: - resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} - engines: {node: '>=4'} - - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} - - commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} - - compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} - - compression@1.8.1: - resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} - engines: {node: '>= 0.8.0'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - connect@3.7.0: - resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} - engines: {node: '>= 0.10.0'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - core-js-compat@3.45.1: - resolution: {integrity: sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==} - - cosmiconfig@5.2.1: - resolution: {integrity: sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==} - engines: {node: '>=4'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - crypto-random-string@2.0.0: - resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} - engines: {node: '>=8'} - - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decode-uri-component@0.2.2: - resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} - engines: {node: '>=0.10'} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - - define-lazy-prop@2.0.0: - resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} - engines: {node: '>=8'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - - dotenv-expand@11.0.7: - resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} - engines: {node: '>=12'} - - dotenv@16.4.7: - resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} - engines: {node: '>=12'} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - electron-to-chromium@1.5.214: - resolution: {integrity: sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - env-editor@0.4.2: - resolution: {integrity: sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA==} - engines: {node: '>=8'} - - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - - error-stack-parser@2.1.4: - resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - - exec-async@2.2.0: - resolution: {integrity: sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw==} - - expo-apple-authentication@7.2.4: - resolution: {integrity: sha512-T2agaLLPT4Ax97FeXImB7BCCEzEJ0gB+ZwlFa/FXBtbp6WFKcGRlTVKiX2YPYLZzN5QjXcmQ9HHJ17jRthNHMg==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-asset@11.1.7: - resolution: {integrity: sha512-b5P8GpjUh08fRCf6m5XPVAh7ra42cQrHBIMgH2UXP+xsj4Wufl6pLy6jRF5w6U7DranUMbsXm8TOyq4EHy7ADg==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - - expo-blur@14.1.5: - resolution: {integrity: sha512-CCLJHxN4eoAl06ESKT3CbMasJ98WsjF9ZQEJnuxtDb9ffrYbZ+g9ru84fukjNUOTtc8A8yXE5z8NgY1l0OMrmQ==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - - expo-clipboard@7.1.5: - resolution: {integrity: sha512-TCANUGOxouoJXxKBW5ASJl2WlmQLGpuZGemDCL2fO5ZMl57DGTypUmagb0CVUFxDl0yAtFIcESd78UsF9o64aw==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - - expo-constants@17.1.7: - resolution: {integrity: sha512-byBjGsJ6T6FrLlhOBxw4EaiMXrZEn/MlUYIj/JAd+FS7ll5X/S4qVRbIimSJtdW47hXMq0zxPfJX6njtA56hHA==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-crypto@14.1.5: - resolution: {integrity: sha512-ZXJoUMoUeiMNEoSD4itItFFz3cKrit6YJ/BR0hjuwNC+NczbV9rorvhvmeJmrU9O2cFQHhJQQR1fjQnt45Vu4Q==} - peerDependencies: - expo: '*' - - expo-document-picker@13.1.6: - resolution: {integrity: sha512-8FTQPDOkyCvFN/i4xyqzH7ELW4AsB6B3XBZQjn1FEdqpozo6rpNJRr7sWFU/93WrLgA9FJEKpKbyr6XxczK6BA==} - peerDependencies: - expo: '*' - - expo-file-system@18.1.11: - resolution: {integrity: sha512-HJw/m0nVOKeqeRjPjGdvm+zBi5/NxcdPf8M8P3G2JFvH5Z8vBWqVDic2O58jnT1OFEy0XXzoH9UqFu7cHg9DTQ==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-font@13.3.2: - resolution: {integrity: sha512-wUlMdpqURmQ/CNKK/+BIHkDA5nGjMqNlYmW0pJFXY/KE/OG80Qcavdu2sHsL4efAIiNGvYdBS10WztuQYU4X0A==} - peerDependencies: - expo: '*' - react: '*' - - expo-haptics@14.1.4: - resolution: {integrity: sha512-QZdE3NMX74rTuIl82I+n12XGwpDWKb8zfs5EpwsnGi/D/n7O2Jd4tO5ivH+muEG/OCJOMq5aeaVDqqaQOhTkcA==} - peerDependencies: - expo: '*' - - expo-image@2.2.1: - resolution: {integrity: sha512-5ZSggMi0X2G9AN0aM+sdkCyyZ6YcWvGs9KYLYrRBVUN3ph6RBiu6mKGpaNN1TAscySRnH1eHbUE1H+Qeq7qm1g==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - react-native-web: '*' - peerDependenciesMeta: - react-native-web: - optional: true - - expo-keep-awake@14.1.4: - resolution: {integrity: sha512-wU9qOnosy4+U4z/o4h8W9PjPvcFMfZXrlUoKTMBW7F4pLqhkkP/5G4EviPZixv4XWFMjn1ExQ5rV6BX8GwJsWA==} - peerDependencies: - expo: '*' - react: '*' - - expo-linking@7.1.7: - resolution: {integrity: sha512-ZJaH1RIch2G/M3hx2QJdlrKbYFUTOjVVW4g39hfxrE5bPX9xhZUYXqxqQtzMNl1ylAevw9JkgEfWbBWddbZ3UA==} - peerDependencies: - react: '*' - react-native: '*' - - expo-modules-autolinking@2.1.14: - resolution: {integrity: sha512-nT5ERXwc+0ZT/pozDoJjYZyUQu5RnXMk9jDGm5lg+PiKvsrCTSA/2/eftJGMxLkTjVI2MXp5WjSz3JRjbA7UXA==} - hasBin: true - - expo-modules-core@2.5.0: - resolution: {integrity: sha512-aIbQxZE2vdCKsolQUl6Q9Farlf8tjh/ROR4hfN1qT7QBGPl1XrJGnaOKkcgYaGrlzCPg/7IBe0Np67GzKMZKKQ==} - - expo-router@5.0.7: - resolution: {integrity: sha512-NlEgRXCKtseDuIHBp87UfkvqsuVrc0MYG+zg33dopaN6wik4RkrWWxUYdNPHub0s/7qMye6zZBY4ZCrXwd/xpA==} - peerDependencies: - '@react-navigation/drawer': ^7.3.9 - '@testing-library/jest-native': '*' - expo: '*' - expo-constants: '*' - expo-linking: '*' - react-native-reanimated: '*' - react-native-safe-area-context: '*' - react-native-screens: '*' - peerDependenciesMeta: - '@react-navigation/drawer': - optional: true - '@testing-library/jest-native': - optional: true - react-native-reanimated: - optional: true - - expo-sharing@13.1.5: - resolution: {integrity: sha512-X/5sAEiWXL2kdoGE3NO5KmbfcmaCWuWVZXHu8OQef7Yig4ZgHFkGD11HKJ5KqDrDg+SRZe4ISd6MxE7vGUgm4w==} - peerDependencies: - expo: '*' - - expo-splash-screen@0.30.10: - resolution: {integrity: sha512-Tt9va/sLENQDQYeOQ6cdLdGvTZ644KR3YG9aRlnpcs2/beYjOX1LHT510EGzVN9ljUTg+1ebEo5GGt2arYtPjw==} - peerDependencies: - expo: '*' - - expo-status-bar@2.2.3: - resolution: {integrity: sha512-+c8R3AESBoduunxTJ8353SqKAKpxL6DvcD8VKBuh81zzJyUUbfB4CVjr1GufSJEKsMzNPXZU+HJwXx7Xh7lx8Q==} - peerDependencies: - react: '*' - react-native: '*' - - expo-symbols@0.4.5: - resolution: {integrity: sha512-ZbgvJfACPfWaJxJrUd0YzDmH9X0Ci7vb5m0/ZpDz/tnF1vQJlkovvpFEHLUmCDSLIN7/fNK8t696KSpzfm8/kg==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-system-ui@5.0.10: - resolution: {integrity: sha512-BTXbSyJr80yuN6VO4XQKZj7BjesZQLHgOYZ0bWyf4VB19GFZq7ZnZOEc/eoKk1B3eIocOMKUfNCrg/Wn8Kfcuw==} - peerDependencies: - expo: '*' - react-native: '*' - react-native-web: '*' - peerDependenciesMeta: - react-native-web: - optional: true - - expo-web-browser@14.1.6: - resolution: {integrity: sha512-/4P8eWqRyfXIMZna3acg320LXNA+P2cwyEVbjDX8vHnWU+UnOtyRKWy3XaAIyMPQ9hVjBNUQTh4MPvtnPRzakw==} - peerDependencies: - expo: '*' - react-native: '*' - - expo@53.0.22: - resolution: {integrity: sha512-sJ2I4W/e5iiM4u/wYCe3qmW4D7WPCRqByPDD0hJcdYNdjc9HFFFdO4OAudZVyC/MmtoWZEIH5kTJP1cw9FjzYA==} - hasBin: true - peerDependencies: - '@expo/dom-webview': '*' - '@expo/metro-runtime': '*' - react: '*' - react-native: '*' - react-native-webview: '*' - peerDependenciesMeta: - '@expo/dom-webview': - optional: true - '@expo/metro-runtime': - optional: true - react-native-webview: - optional: true - - exponential-backoff@3.1.2: - resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - - fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - filter-obj@1.1.0: - resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} - engines: {node: '>=0.10.0'} - - finalhandler@1.1.2: - resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} - engines: {node: '>= 0.8'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flow-enums-runtime@0.0.6: - resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} - - fontfaceobserver@2.3.0: - resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - freeport-async@2.0.0: - resolution: {integrity: sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==} - engines: {node: '>=8'} - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - - getenv@2.0.0: - resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} - engines: {node: '>=6'} - - glob@12.0.0: - resolution: {integrity: sha512-5Qcll1z7IKgHr5g485ePDdHcNQY0k2dtv/bjYy0iuyGxQw2qSOiiXUXJ+AYQpg3HNoUMHqAruX478Jeev7UULw==} - engines: {node: 20 || >=22} - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - - hermes-estree@0.29.1: - resolution: {integrity: sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==} - - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - - hermes-parser@0.29.1: - resolution: {integrity: sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==} - - hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - - hosted-git-info@7.0.2: - resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} - engines: {node: ^16.14.0 || >=18.0.0} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - image-size@1.2.1: - resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} - engines: {node: '>=16.x'} - hasBin: true - - import-fresh@2.0.0: - resolution: {integrity: sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==} - engines: {node: '>=4'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - invariant@2.2.4: - resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - is-directory@0.3.1: - resolution: {integrity: sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==} - engines: {node: '>=0.10.0'} - - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - - jackspeak@4.1.1: - resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} - engines: {node: 20 || >=22} - - jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jimp-compact@0.16.1: - resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsc-safe-url@0.2.4: - resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} - - jsesc@3.0.2: - resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} - engines: {node: '>=6'} - hasBin: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-parse-better-errors@1.0.2: - resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - - lan-network@0.1.7: - resolution: {integrity: sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ==} - hasBin: true - - leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - - lighthouse-logger@1.4.2: - resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} - - lightningcss-darwin-arm64@1.27.0: - resolution: {integrity: sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.27.0: - resolution: {integrity: sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.27.0: - resolution: {integrity: sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.27.0: - resolution: {integrity: sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.27.0: - resolution: {integrity: sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-arm64-musl@1.27.0: - resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-x64-gnu@1.27.0: - resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-linux-x64-musl@1.27.0: - resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-win32-arm64-msvc@1.27.0: - resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.27.0: - resolution: {integrity: sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.27.0: - resolution: {integrity: sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==} - engines: {node: '>= 12.0.0'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - - lodash.throttle@4.1.1: - resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} - - log-symbols@2.2.0: - resolution: {integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==} - engines: {node: '>=4'} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@11.2.2: - resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} - engines: {node: 20 || >=22} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - - marky@1.3.0: - resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} - - memoize-one@5.2.1: - resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - - merge-options@3.0.4: - resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} - engines: {node: '>=10'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - metro-babel-transformer@0.82.5: - resolution: {integrity: sha512-W/scFDnwJXSccJYnOFdGiYr9srhbHPdxX9TvvACOFsIXdLilh3XuxQl/wXW6jEJfgIb0jTvoTlwwrqvuwymr6Q==} - engines: {node: '>=18.18'} - - metro-cache-key@0.82.5: - resolution: {integrity: sha512-qpVmPbDJuRLrT4kcGlUouyqLGssJnbTllVtvIgXfR7ZuzMKf0mGS+8WzcqzNK8+kCyakombQWR0uDd8qhWGJcA==} - engines: {node: '>=18.18'} - - metro-cache@0.82.5: - resolution: {integrity: sha512-AwHV9607xZpedu1NQcjUkua8v7HfOTKfftl6Vc9OGr/jbpiJX6Gpy8E/V9jo/U9UuVYX2PqSUcVNZmu+LTm71Q==} - engines: {node: '>=18.18'} - - metro-config@0.82.5: - resolution: {integrity: sha512-/r83VqE55l0WsBf8IhNmc/3z71y2zIPe5kRSuqA5tY/SL/ULzlHUJEMd1szztd0G45JozLwjvrhAzhDPJ/Qo/g==} - engines: {node: '>=18.18'} - - metro-core@0.82.5: - resolution: {integrity: sha512-OJL18VbSw2RgtBm1f2P3J5kb892LCVJqMvslXxuxjAPex8OH7Eb8RBfgEo7VZSjgb/LOf4jhC4UFk5l5tAOHHA==} - engines: {node: '>=18.18'} - - metro-file-map@0.82.5: - resolution: {integrity: sha512-vpMDxkGIB+MTN8Af5hvSAanc6zXQipsAUO+XUx3PCQieKUfLwdoa8qaZ1WAQYRpaU+CJ8vhBcxtzzo3d9IsCIQ==} - engines: {node: '>=18.18'} - - metro-minify-terser@0.82.5: - resolution: {integrity: sha512-v6Nx7A4We6PqPu/ta1oGTqJ4Usz0P7c+3XNeBxW9kp8zayS3lHUKR0sY0wsCHInxZlNAEICx791x+uXytFUuwg==} - engines: {node: '>=18.18'} - - metro-resolver@0.82.5: - resolution: {integrity: sha512-kFowLnWACt3bEsuVsaRNgwplT8U7kETnaFHaZePlARz4Fg8tZtmRDUmjaD68CGAwc0rwdwNCkWizLYpnyVcs2g==} - engines: {node: '>=18.18'} - - metro-runtime@0.82.5: - resolution: {integrity: sha512-rQZDoCUf7k4Broyw3Ixxlq5ieIPiR1ULONdpcYpbJQ6yQ5GGEyYjtkztGD+OhHlw81LCR2SUAoPvtTus2WDK5g==} - engines: {node: '>=18.18'} - - metro-source-map@0.82.5: - resolution: {integrity: sha512-wH+awTOQJVkbhn2SKyaw+0cd+RVSCZ3sHVgyqJFQXIee/yLs3dZqKjjeKKhhVeudgjXo7aE/vSu/zVfcQEcUfw==} - engines: {node: '>=18.18'} - - metro-symbolicate@0.82.5: - resolution: {integrity: sha512-1u+07gzrvYDJ/oNXuOG1EXSvXZka/0JSW1q2EYBWerVKMOhvv9JzDGyzmuV7hHbF2Hg3T3S2uiM36sLz1qKsiw==} - engines: {node: '>=18.18'} - hasBin: true - - metro-transform-plugins@0.82.5: - resolution: {integrity: sha512-57Bqf3rgq9nPqLrT2d9kf/2WVieTFqsQ6qWHpEng5naIUtc/Iiw9+0bfLLWSAw0GH40iJ4yMjFcFJDtNSYynMA==} - engines: {node: '>=18.18'} - - metro-transform-worker@0.82.5: - resolution: {integrity: sha512-mx0grhAX7xe+XUQH6qoHHlWedI8fhSpDGsfga7CpkO9Lk9W+aPitNtJWNGrW8PfjKEWbT9Uz9O50dkI8bJqigw==} - engines: {node: '>=18.18'} - - metro@0.82.5: - resolution: {integrity: sha512-8oAXxL7do8QckID/WZEKaIFuQJFUTLzfVcC48ghkHhNK2RGuQq8Xvf4AVd+TUA0SZtX0q8TGNXZ/eba1ckeGCg==} - engines: {node: '>=18.18'} - hasBin: true - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - - mimic-fn@1.2.0: - resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} - engines: {node: '>=4'} - - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - - minizlib@3.0.2: - resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} - engines: {node: '>= 18'} - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - mkdirp@3.0.1: - resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} - engines: {node: '>=10'} - hasBin: true - - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - - nested-error-stacks@2.0.1: - resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} - - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} - engines: {node: '>= 6.13.0'} - - node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - npm-package-arg@11.0.3: - resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} - engines: {node: ^16.14.0 || >=18.0.0} - - nullthrows@1.1.1: - resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - - ob1@0.82.5: - resolution: {integrity: sha512-QyQQ6e66f+Ut/qUVjEce0E/wux5nAGLXYZDn1jr15JWstHsCH3l6VVrg8NKDptW9NEiBXKOJeGF/ydxeSDF3IQ==} - engines: {node: '>=18.18'} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - on-headers@1.1.0: - resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@2.0.1: - resolution: {integrity: sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==} - engines: {node: '>=4'} - - open@7.4.2: - resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} - engines: {node: '>=8'} - - open@8.4.2: - resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} - engines: {node: '>=12'} - - ora@3.4.0: - resolution: {integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==} - engines: {node: '>=6'} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parse-json@4.0.0: - resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} - engines: {node: '>=4'} - - parse-png@2.1.0: - resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} - engines: {node: '>=10'} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@2.0.1: - resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} - engines: {node: 20 || >=22} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@3.0.1: - resolution: {integrity: sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==} - engines: {node: '>=10'} - - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - - plist@3.1.0: - resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} - engines: {node: '>=10.4.0'} - - pngjs@3.4.0: - resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} - engines: {node: '>=4.0.0'} - - postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} - engines: {node: ^10 || ^12 || >=14} - - pretty-bytes@5.6.0: - resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} - engines: {node: '>=6'} - - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - proc-log@4.2.0: - resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - promise@8.3.0: - resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} - - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qrcode-terminal@0.11.0: - resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} - hasBin: true - - query-string@7.1.3: - resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} - engines: {node: '>=6'} - - queue@6.0.2: - resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - - react-devtools-core@6.1.5: - resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} - - react-fast-compare@3.2.2: - resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} - - react-freeze@1.0.4: - resolution: {integrity: sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==} - engines: {node: '>=10'} - peerDependencies: - react: '>=17.0.0' - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - react-is@19.1.1: - resolution: {integrity: sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==} - - react-native-edge-to-edge@1.6.0: - resolution: {integrity: sha512-2WCNdE3Qd6Fwg9+4BpbATUxCLcouF6YRY7K+J36KJ4l3y+tWN6XCqAC4DuoGblAAbb2sLkhEDp4FOlbOIot2Og==} - peerDependencies: - react: '*' - react-native: '*' - - react-native-gesture-handler@2.24.0: - resolution: {integrity: sha512-ZdWyOd1C8axKJHIfYxjJKCcxjWEpUtUWgTOVY2wynbiveSQDm8X/PDyAKXSer/GOtIpjudUbACOndZXCN3vHsw==} - peerDependencies: - react: '*' - react-native: '*' - - react-native-is-edge-to-edge@1.1.7: - resolution: {integrity: sha512-EH6i7E8epJGIcu7KpfXYXiV2JFIYITtq+rVS8uEb+92naMRBdxhTuS8Wn2Q7j9sqyO0B+Xbaaf9VdipIAmGW4w==} - peerDependencies: - react: '*' - react-native: '*' - - react-native-is-edge-to-edge@1.2.1: - resolution: {integrity: sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==} - peerDependencies: - react: '*' - react-native: '*' - - react-native-reanimated@3.17.5: - resolution: {integrity: sha512-SxBK7wQfJ4UoWoJqQnmIC7ZjuNgVb9rcY5Xc67upXAFKftWg0rnkknTw6vgwnjRcvYThrjzUVti66XoZdDJGtw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - react: '*' - react-native: '*' - - react-native-safe-area-context@5.4.0: - resolution: {integrity: sha512-JaEThVyJcLhA+vU0NU8bZ0a1ih6GiF4faZ+ArZLqpYbL6j7R3caRqj+mE3lEtKCuHgwjLg3bCxLL1GPUJZVqUA==} - peerDependencies: - react: '*' - react-native: '*' - - react-native-screens@4.15.4: - resolution: {integrity: sha512-aKHPDScUbpQiZEG9eZssHdG5jEQs4yiJ8eMx6g81Ex/xU7DZkv3911enzdCb+v4eJE79X8waizY0ZhauZJQmrw==} - peerDependencies: - react: '*' - react-native: '*' - - react-native-webview@13.13.5: - resolution: {integrity: sha512-MfC2B+woL4Hlj2WCzcb1USySKk+SteXnUKmKktOk/H/AQy5+LuVdkPKm8SknJ0/RxaxhZ48WBoTRGaqgR137hw==} - peerDependencies: - react: '*' - react-native: '*' - - react-native@0.79.3: - resolution: {integrity: sha512-EzH1+9gzdyEo9zdP6u7Sh3Jtf5EOMwzy+TK65JysdlgAzfEVfq4mNeXcAZ6SmD+CW6M7ARJbvXLyTD0l2S5rpg==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@types/react': ^19.0.0 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-refresh@0.14.2: - resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} - engines: {node: '>=0.10.0'} - - react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} - engines: {node: '>=0.10.0'} - - regenerate-unicode-properties@10.2.0: - resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} - engines: {node: '>=4'} - - regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - - regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - - regexpu-core@6.2.0: - resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} - engines: {node: '>=4'} - - regjsgen@0.8.0: - resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - - regjsparser@0.12.0: - resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} - hasBin: true - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - requireg@0.2.2: - resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} - engines: {node: '>= 4.0.0'} - - resolve-from@3.0.0: - resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} - engines: {node: '>=4'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve-workspace-root@2.0.0: - resolution: {integrity: sha512-IsaBUZETJD5WsI11Wt8PKHwaIe45or6pwNc8yflvLJ4DWtImK9kuLoH5kUva/2Mmx/RdIyr4aONNSa2v9LTJsw==} - - resolve.exports@2.0.3: - resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} - engines: {node: '>=10'} - - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - - resolve@1.7.1: - resolution: {integrity: sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==} - - restore-cursor@2.0.0: - resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} - engines: {node: '>=4'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - sax@1.4.1: - resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} - - scheduler@0.25.0: - resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} - - schema-utils@4.3.2: - resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} - engines: {node: '>= 10.13.0'} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} - engines: {node: '>=10'} - hasBin: true - - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - - send@0.19.1: - resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} - engines: {node: '>= 0.8.0'} - - serialize-error@2.1.0: - resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} - engines: {node: '>=0.10.0'} - - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - - server-only@0.0.1: - resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sf-symbols-typescript@2.1.0: - resolution: {integrity: sha512-ezT7gu/SHTPIOEEoG6TF+O0m5eewl0ZDAO4AtdBi5HjsrUI6JdCG17+Q8+aKp0heM06wZKApRCn5olNbs0Wb/A==} - engines: {node: '>=10'} - - shallowequal@1.1.0: - resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-plist@1.3.1: - resolution: {integrity: sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==} - - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - slugify@1.6.6: - resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==} - engines: {node: '>=8.0.0'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - split-on-first@1.1.0: - resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} - engines: {node: '>=6'} - - stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - - stackframe@1.3.4: - resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} - - stacktrace-parser@0.1.11: - resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} - engines: {node: '>=6'} - - statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - stream-buffers@2.2.0: - resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==} - engines: {node: '>= 0.10.0'} - - strict-uri-encode@2.0.0: - resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} - engines: {node: '>=4'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - strip-ansi@5.2.0: - resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} - engines: {node: '>=6'} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - structured-headers@0.4.1: - resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==} - - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - supports-hyperlinks@2.3.0: - resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} - engines: {node: '>=8'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tar@7.4.3: - resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} - engines: {node: '>=18'} - - temp-dir@2.0.0: - resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} - engines: {node: '>=8'} - - terminal-link@2.1.1: - resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} - engines: {node: '>=8'} - - terser@5.44.0: - resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} - engines: {node: '>=10'} - hasBin: true - - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - - throat@5.0.0: - resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} - - tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - - type-fest@0.7.1: - resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} - engines: {node: '>=8'} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici@6.21.3: - resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==} - engines: {node: '>=18.17'} - - undici@7.15.0: - resolution: {integrity: sha512-7oZJCPvvMvTd0OlqWsIxTuItTpJBpU1tcbVl24FMn3xt3+VSunwUasmfPJRE57oNO1KsZ4PgA1xTdAX4hq8NyQ==} - engines: {node: '>=20.18.1'} - - unicode-canonical-property-names-ecmascript@2.0.1: - resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} - engines: {node: '>=4'} - - unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} - - unicode-match-property-value-ecmascript@2.2.0: - resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} - engines: {node: '>=4'} - - unicode-property-aliases-ecmascript@2.1.0: - resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} - engines: {node: '>=4'} - - unique-string@2.0.0: - resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} - engines: {node: '>=8'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - use-latest-callback@0.2.4: - resolution: {integrity: sha512-LS2s2n1usUUnDq4oVh1ca6JFX9uSqUncTfAm44WMg0v6TxL7POUTk1B044NH8TeLkFbNajIsgDHcgNpNzZucdg==} - peerDependencies: - react: '>=16.8' - - use-sync-external-store@1.5.0: - resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - uuid@7.0.3: - resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} - hasBin: true - - validate-npm-package-name@5.0.1: - resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - vlq@1.0.1: - resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} - - walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - - warn-once@0.1.1: - resolution: {integrity: sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==} - - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - - webidl-conversions@5.0.0: - resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} - engines: {node: '>=8'} - - whatwg-fetch@3.6.20: - resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} - - whatwg-url-without-unicode@8.0.0-3: - resolution: {integrity: sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==} - engines: {node: '>=10'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - wonka@6.3.5: - resolution: {integrity: sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw==} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - ws@6.2.3: - resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xcode@3.0.1: - resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==} - engines: {node: '>=10.0.0'} - - xml2js@0.6.0: - resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==} - engines: {node: '>=4.0.0'} - - xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - - xmlbuilder@15.1.1: - resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} - engines: {node: '>=8.0'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yallist@5.0.0: - resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} - engines: {node: '>=18'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - -snapshots: - - '@0no-co/graphql.web@1.2.0': {} - - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 - - '@babel/code-frame@7.10.4': - dependencies: - '@babel/highlight': 7.25.9 - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.0': {} - - '@babel/core@7.28.3': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) - '@babel/helpers': 7.28.3 - '@babel/parser': 7.28.3 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - convert-source-map: 2.0.0 - debug: 4.4.1 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.3': - dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.28.2 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.4 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - regexpu-core: 6.2.0 - semver: 6.3.1 - - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.1 - lodash.debounce: 4.0.8 - resolve: 1.22.10 - transitivePeerDependencies: - - supports-color - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-member-expression-to-functions@7.27.1': - dependencies: - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.28.2 - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.27.1': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helper-wrap-function@7.28.3': - dependencies: - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color - - '@babel/helpers@7.28.3': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.2 - - '@babel/highlight@7.25.9': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/parser@7.28.3': - dependencies: - '@babel/types': 7.28.2 - - '@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-decorators': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-export-default-from@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-decorators@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-export-default-from@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-flow@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-block-scoping@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-classes@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.2 - - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-flow-strip-types@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-flow': 7.27.1(@babel/core@7.28.3) - - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-object-rest-spread@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-regenerator@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-runtime@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.3) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.3) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.3) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-typescript@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/preset-react@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/preset-typescript@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/runtime@7.28.3': {} - - '@babel/template@7.27.2': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - - '@babel/traverse@7.28.3': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.3 - '@babel/template': 7.27.2 - '@babel/types': 7.28.2 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.28.2': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - - '@egjs/hammerjs@2.0.17': - dependencies: - '@types/hammerjs': 2.0.46 - - '@expo/cli@0.24.21': - dependencies: - '@0no-co/graphql.web': 1.2.0 - '@babel/runtime': 7.28.3 - '@expo/code-signing-certificates': 0.0.5 - '@expo/config': 11.0.13 - '@expo/config-plugins': 10.1.2 - '@expo/devcert': 1.2.0 - '@expo/env': 1.0.7 - '@expo/image-utils': 0.7.6 - '@expo/json-file': 9.1.5 - '@expo/metro-config': 0.20.17 - '@expo/osascript': 2.2.5 - '@expo/package-manager': 1.8.6 - '@expo/plist': 0.3.5 - '@expo/prebuild-config': 9.0.11 - '@expo/schema-utils': 0.1.0 - '@expo/spawn-async': 1.7.2 - '@expo/ws-tunnel': 1.0.6 - '@expo/xcpretty': 4.3.2 - '@react-native/dev-middleware': 0.79.6 - '@urql/core': 5.2.0 - '@urql/exchange-retry': 1.3.2(@urql/core@5.2.0) - accepts: 1.3.8 - arg: 5.0.2 - better-opn: 3.0.2 - bplist-creator: 0.1.0 - bplist-parser: 0.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - compression: 1.8.1 - connect: 3.7.0 - debug: 4.4.1 - env-editor: 0.4.2 - freeport-async: 2.0.0 - getenv: 2.0.0 - glob: 12.0.0 - lan-network: 0.1.7 - minimatch: 9.0.5 - node-forge: 1.3.1 - npm-package-arg: 11.0.3 - ora: 3.4.0 - picomatch: 3.0.1 - pretty-bytes: 5.6.0 - pretty-format: 29.7.0 - progress: 2.0.3 - prompts: 2.4.2 - qrcode-terminal: 0.11.0 - require-from-string: 2.0.2 - requireg: 0.2.2 - resolve: 1.22.10 - resolve-from: 5.0.0 - resolve.exports: 2.0.3 - semver: 7.7.2 - send: 0.19.1 - slugify: 1.6.6 - source-map-support: 0.5.21 - stacktrace-parser: 0.1.11 - structured-headers: 0.4.1 - tar: 7.4.3 - terminal-link: 2.1.1 - undici: 6.21.3 - wrap-ansi: 7.0.0 - ws: 8.18.3 - transitivePeerDependencies: - - bufferutil - - graphql - - supports-color - - utf-8-validate - - '@expo/code-signing-certificates@0.0.5': - dependencies: - node-forge: 1.3.1 - nullthrows: 1.1.1 - - '@expo/config-plugins@10.1.2': - dependencies: - '@expo/config-types': 53.0.5 - '@expo/json-file': 9.1.5 - '@expo/plist': 0.3.5 - '@expo/sdk-runtime-versions': 1.0.0 - chalk: 4.1.2 - debug: 4.4.1 - getenv: 2.0.0 - glob: 12.0.0 - resolve-from: 5.0.0 - semver: 7.7.2 - slash: 3.0.0 - slugify: 1.6.6 - xcode: 3.0.1 - xml2js: 0.6.0 - transitivePeerDependencies: - - supports-color - - '@expo/config-types@53.0.5': {} - - '@expo/config@11.0.13': - dependencies: - '@babel/code-frame': 7.10.4 - '@expo/config-plugins': 10.1.2 - '@expo/config-types': 53.0.5 - '@expo/json-file': 9.1.5 - deepmerge: 4.3.1 - getenv: 2.0.0 - glob: 12.0.0 - require-from-string: 2.0.2 - resolve-from: 5.0.0 - resolve-workspace-root: 2.0.0 - semver: 7.7.2 - slugify: 1.6.6 - sucrase: 3.35.0 - transitivePeerDependencies: - - supports-color - - '@expo/devcert@1.2.0': - dependencies: - '@expo/sudo-prompt': 9.3.2 - debug: 3.2.7 - glob: 12.0.0 - transitivePeerDependencies: - - supports-color - - '@expo/env@1.0.7': - dependencies: - chalk: 4.1.2 - debug: 4.4.1 - dotenv: 16.4.7 - dotenv-expand: 11.0.7 - getenv: 2.0.0 - transitivePeerDependencies: - - supports-color - - '@expo/fingerprint@0.13.4': - dependencies: - '@expo/spawn-async': 1.7.2 - arg: 5.0.2 - chalk: 4.1.2 - debug: 4.4.1 - find-up: 5.0.0 - getenv: 2.0.0 - glob: 12.0.0 - ignore: 5.3.2 - minimatch: 9.0.5 - p-limit: 3.1.0 - resolve-from: 5.0.0 - semver: 7.7.2 - transitivePeerDependencies: - - supports-color - - '@expo/image-utils@0.7.6': - dependencies: - '@expo/spawn-async': 1.7.2 - chalk: 4.1.2 - getenv: 2.0.0 - jimp-compact: 0.16.1 - parse-png: 2.1.0 - resolve-from: 5.0.0 - semver: 7.7.2 - temp-dir: 2.0.0 - unique-string: 2.0.0 - - '@expo/json-file@9.1.5': - dependencies: - '@babel/code-frame': 7.10.4 - json5: 2.2.3 - - '@expo/metro-config@0.20.17': - dependencies: - '@babel/core': 7.28.3 - '@babel/generator': 7.28.3 - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - '@expo/config': 11.0.13 - '@expo/env': 1.0.7 - '@expo/json-file': 9.1.5 - '@expo/spawn-async': 1.7.2 - chalk: 4.1.2 - debug: 4.4.1 - dotenv: 16.4.7 - dotenv-expand: 11.0.7 - getenv: 2.0.0 - glob: 12.0.0 - jsc-safe-url: 0.2.4 - lightningcss: 1.27.0 - minimatch: 9.0.5 - postcss: 8.4.49 - resolve-from: 5.0.0 - transitivePeerDependencies: - - supports-color - - '@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))': - dependencies: - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - '@expo/osascript@2.2.5': - dependencies: - '@expo/spawn-async': 1.7.2 - exec-async: 2.2.0 - - '@expo/package-manager@1.8.6': - dependencies: - '@expo/json-file': 9.1.5 - '@expo/spawn-async': 1.7.2 - chalk: 4.1.2 - npm-package-arg: 11.0.3 - ora: 3.4.0 - resolve-workspace-root: 2.0.0 - - '@expo/plist@0.3.5': - dependencies: - '@xmldom/xmldom': 0.8.11 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - - '@expo/prebuild-config@9.0.11': - dependencies: - '@expo/config': 11.0.13 - '@expo/config-plugins': 10.1.2 - '@expo/config-types': 53.0.5 - '@expo/image-utils': 0.7.6 - '@expo/json-file': 9.1.5 - '@react-native/normalize-colors': 0.79.5 - debug: 4.4.1 - resolve-from: 5.0.0 - semver: 7.7.2 - xml2js: 0.6.0 - transitivePeerDependencies: - - supports-color - - '@expo/schema-utils@0.1.0': {} - - '@expo/sdk-runtime-versions@1.0.0': {} - - '@expo/server@0.6.3': - dependencies: - abort-controller: 3.0.0 - debug: 4.4.1 - source-map-support: 0.5.21 - undici: 7.15.0 - transitivePeerDependencies: - - supports-color - - '@expo/spawn-async@1.7.2': - dependencies: - cross-spawn: 7.0.6 - - '@expo/sudo-prompt@9.3.2': {} - - '@expo/vector-icons@14.1.0(expo-font@13.3.2(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)': - dependencies: - expo-font: 13.3.2(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - '@expo/ws-tunnel@1.0.6': {} - - '@expo/xcpretty@4.3.2': - dependencies: - '@babel/code-frame': 7.10.4 - chalk: 4.1.2 - find-up: 5.0.0 - js-yaml: 4.1.1 - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@isaacs/fs-minipass@4.0.1': - dependencies: - minipass: 7.1.2 - - '@isaacs/ttlcache@1.4.1': {} - - '@istanbuljs/load-nyc-config@1.1.0': - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 4.1.1 - resolve-from: 5.0.0 - - '@istanbuljs/schema@0.1.3': {} - - '@jest/create-cache-key-function@29.7.0': - dependencies: - '@jest/types': 29.6.3 - - '@jest/environment@29.7.0': - dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.1 - jest-mock: 29.7.0 - - '@jest/fake-timers@29.7.0': - dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 - '@types/node': 22.18.1 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 - - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - - '@jest/transform@29.7.0': - dependencies: - '@babel/core': 7.28.3 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.30 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 - pirates: 4.0.7 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - - '@jest/types@29.6.3': - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 22.18.1 - '@types/yargs': 17.0.33 - chalk: 4.1.2 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.30 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/source-map@0.3.11': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.30': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.0.14)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.14 - - '@radix-ui/react-slot@1.2.0(@types/react@19.0.14)(react@19.0.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.14)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.14 - - '@react-native-async-storage/async-storage@2.2.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))': - dependencies: - merge-options: 3.0.4 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - '@react-native/assets-registry@0.79.3': {} - - '@react-native/babel-plugin-codegen@0.79.6(@babel/core@7.28.3)': - dependencies: - '@babel/traverse': 7.28.3 - '@react-native/codegen': 0.79.6(@babel/core@7.28.3) - transitivePeerDependencies: - - '@babel/core' - - supports-color - - '@react-native/babel-preset@0.79.6(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-export-default-from': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-block-scoping': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-classes': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-object-rest-spread': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-regenerator': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-runtime': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.3) - '@babel/template': 7.27.2 - '@react-native/babel-plugin-codegen': 0.79.6(@babel/core@7.28.3) - babel-plugin-syntax-hermes-parser: 0.25.1 - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.28.3) - react-refresh: 0.14.2 - transitivePeerDependencies: - - supports-color - - '@react-native/codegen@0.79.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - glob: 7.2.3 - hermes-parser: 0.25.1 - invariant: 2.2.4 - nullthrows: 1.1.1 - yargs: 17.7.2 - - '@react-native/codegen@0.79.6(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/parser': 7.28.3 - glob: 7.2.3 - hermes-parser: 0.25.1 - invariant: 2.2.4 - nullthrows: 1.1.1 - yargs: 17.7.2 - - '@react-native/community-cli-plugin@0.79.3': - dependencies: - '@react-native/dev-middleware': 0.79.3 - chalk: 4.1.2 - debug: 2.6.9 - invariant: 2.2.4 - metro: 0.82.5 - metro-config: 0.82.5 - metro-core: 0.82.5 - semver: 7.7.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/debugger-frontend@0.79.3': {} - - '@react-native/debugger-frontend@0.79.6': {} - - '@react-native/dev-middleware@0.79.3': - dependencies: - '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.79.3 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 0.2.0 - connect: 3.7.0 - debug: 2.6.9 - invariant: 2.2.4 - nullthrows: 1.1.1 - open: 7.4.2 - serve-static: 1.16.2 - ws: 6.2.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/dev-middleware@0.79.6': - dependencies: - '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.79.6 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 0.2.0 - connect: 3.7.0 - debug: 2.6.9 - invariant: 2.2.4 - nullthrows: 1.1.1 - open: 7.4.2 - serve-static: 1.16.2 - ws: 6.2.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/gradle-plugin@0.79.3': {} - - '@react-native/js-polyfills@0.79.3': {} - - '@react-native/normalize-colors@0.79.3': {} - - '@react-native/normalize-colors@0.79.5': {} - - '@react-native/virtualized-lists@0.79.3(@types/react@19.0.14)(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.14 - - '@react-navigation/bottom-tabs@7.4.7(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-screens@4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)': - dependencies: - '@react-navigation/elements': 2.6.4(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - '@react-navigation/native': 7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - color: 4.2.3 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - react-native-safe-area-context: 5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-screens: 4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - transitivePeerDependencies: - - '@react-native-masked-view/masked-view' - - '@react-navigation/core@7.12.4(react@19.0.0)': - dependencies: - '@react-navigation/routers': 7.5.1 - escape-string-regexp: 4.0.0 - nanoid: 3.3.11 - query-string: 7.1.3 - react: 19.0.0 - react-is: 19.1.1 - use-latest-callback: 0.2.4(react@19.0.0) - use-sync-external-store: 1.5.0(react@19.0.0) - - '@react-navigation/elements@2.6.4(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)': - dependencies: - '@react-navigation/native': 7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - color: 4.2.3 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - react-native-safe-area-context: 5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - use-latest-callback: 0.2.4(react@19.0.0) - use-sync-external-store: 1.5.0(react@19.0.0) - - '@react-navigation/native-stack@7.3.26(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-screens@4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)': - dependencies: - '@react-navigation/elements': 2.6.4(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - '@react-navigation/native': 7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - react-native-safe-area-context: 5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-screens: 4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - warn-once: 0.1.1 - transitivePeerDependencies: - - '@react-native-masked-view/masked-view' - - '@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)': - dependencies: - '@react-navigation/core': 7.12.4(react@19.0.0) - escape-string-regexp: 4.0.0 - fast-deep-equal: 3.1.3 - nanoid: 3.3.11 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - use-latest-callback: 0.2.4(react@19.0.0) - - '@react-navigation/routers@7.5.1': - dependencies: - nanoid: 3.3.11 - - '@sinclair/typebox@0.27.8': {} - - '@sinonjs/commons@3.0.1': - dependencies: - type-detect: 4.0.8 - - '@sinonjs/fake-timers@10.3.0': - dependencies: - '@sinonjs/commons': 3.0.1 - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.2 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.28.2 - - '@types/graceful-fs@4.1.9': - dependencies: - '@types/node': 22.18.1 - - '@types/hammerjs@2.0.46': {} - - '@types/istanbul-lib-coverage@2.0.6': {} - - '@types/istanbul-lib-report@3.0.3': - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - - '@types/istanbul-reports@3.0.4': - dependencies: - '@types/istanbul-lib-report': 3.0.3 - - '@types/json-schema@7.0.15': {} - - '@types/node@22.18.1': - dependencies: - undici-types: 6.21.0 - - '@types/react@19.0.14': - dependencies: - csstype: 3.1.3 - - '@types/stack-utils@2.0.3': {} - - '@types/yargs-parser@21.0.3': {} - - '@types/yargs@17.0.33': - dependencies: - '@types/yargs-parser': 21.0.3 - - '@urql/core@5.2.0': - dependencies: - '@0no-co/graphql.web': 1.2.0 - wonka: 6.3.5 - transitivePeerDependencies: - - graphql - - '@urql/exchange-retry@1.3.2(@urql/core@5.2.0)': - dependencies: - '@urql/core': 5.2.0 - wonka: 6.3.5 - - '@xmldom/xmldom@0.8.11': {} - - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - - acorn@8.15.0: {} - - agent-base@7.1.4: {} - - ajv-formats@2.1.1(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 - - ajv-keywords@5.1.0(ajv@8.17.1): - dependencies: - ajv: 8.17.1 - fast-deep-equal: 3.1.3 - - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - anser@1.4.10: {} - - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - - ansi-regex@4.1.1: {} - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.0: {} - - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - ansi-styles@6.2.1: {} - - any-promise@1.3.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - arg@5.0.2: {} - - argparse@2.0.1: {} - - asap@2.0.6: {} - - async-limiter@1.0.1: {} - - babel-jest@29.7.0(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.28.3) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-istanbul@6.1.1: - dependencies: - '@babel/helper-plugin-utils': 7.27.1 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-jest-hoist@29.6.3: - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.2 - '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.28.0 - - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.3): - dependencies: - '@babel/compat-data': 7.28.0 - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - core-js-compat: 3.45.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - babel-plugin-react-native-web@0.19.13: {} - - babel-plugin-syntax-hermes-parser@0.25.1: - dependencies: - hermes-parser: 0.25.1 - - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.28.3): - dependencies: - '@babel/plugin-syntax-flow': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - '@babel/core' - - babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.3) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.3) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.3) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.3) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.3) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.3) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.3) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.3) - - babel-preset-expo@13.2.4(@babel/core@7.28.3): - dependencies: - '@babel/helper-module-imports': 7.27.1 - '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-export-default-from': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-object-rest-spread': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-runtime': 7.28.3(@babel/core@7.28.3) - '@babel/preset-react': 7.27.1(@babel/core@7.28.3) - '@babel/preset-typescript': 7.27.1(@babel/core@7.28.3) - '@react-native/babel-preset': 0.79.6(@babel/core@7.28.3) - babel-plugin-react-native-web: 0.19.13 - babel-plugin-syntax-hermes-parser: 0.25.1 - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.28.3) - debug: 4.4.1 - react-refresh: 0.14.2 - resolve-from: 5.0.0 - transitivePeerDependencies: - - '@babel/core' - - supports-color - - babel-preset-jest@29.6.3(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.3) - - balanced-match@1.0.2: {} - - base64-js@1.5.1: {} - - better-opn@3.0.2: - dependencies: - open: 8.4.2 - - big-integer@1.6.52: {} - - bplist-creator@0.1.0: - dependencies: - stream-buffers: 2.2.0 - - bplist-parser@0.3.1: - dependencies: - big-integer: 1.6.52 - - bplist-parser@0.3.2: - dependencies: - big-integer: 1.6.52 - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.25.4: - dependencies: - caniuse-lite: 1.0.30001739 - electron-to-chromium: 1.5.214 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.25.4) - - bser@2.1.1: - dependencies: - node-int64: 0.4.0 - - buffer-from@1.1.2: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bytes@3.1.2: {} - - caller-callsite@2.0.0: - dependencies: - callsites: 2.0.0 - - caller-path@2.0.0: - dependencies: - caller-callsite: 2.0.0 - - callsites@2.0.0: {} - - camelcase@5.3.1: {} - - camelcase@6.3.0: {} - - caniuse-lite@1.0.30001739: {} - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chownr@3.0.0: {} - - chrome-launcher@0.15.2: - dependencies: - '@types/node': 22.18.1 - escape-string-regexp: 4.0.0 - is-wsl: 2.2.0 - lighthouse-logger: 1.4.2 - transitivePeerDependencies: - - supports-color - - chromium-edge-launcher@0.2.0: - dependencies: - '@types/node': 22.18.1 - escape-string-regexp: 4.0.0 - is-wsl: 2.2.0 - lighthouse-logger: 1.4.2 - mkdirp: 1.0.4 - rimraf: 3.0.2 - transitivePeerDependencies: - - supports-color - - ci-info@2.0.0: {} - - ci-info@3.9.0: {} - - cli-cursor@2.1.0: - dependencies: - restore-cursor: 2.0.0 - - cli-spinners@2.9.2: {} - - client-only@0.0.1: {} - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - clone@1.0.4: {} - - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.3: {} - - color-name@1.1.4: {} - - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - - commander@12.1.0: {} - - commander@2.20.3: {} - - commander@4.1.1: {} - - commander@7.2.0: {} - - compressible@2.0.18: - dependencies: - mime-db: 1.54.0 - - compression@1.8.1: - dependencies: - bytes: 3.1.2 - compressible: 2.0.18 - debug: 2.6.9 - negotiator: 0.6.4 - on-headers: 1.1.0 - safe-buffer: 5.2.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - concat-map@0.0.1: {} - - connect@3.7.0: - dependencies: - debug: 2.6.9 - finalhandler: 1.1.2 - parseurl: 1.3.3 - utils-merge: 1.0.1 - transitivePeerDependencies: - - supports-color - - convert-source-map@2.0.0: {} - - core-js-compat@3.45.1: - dependencies: - browserslist: 4.25.4 - - cosmiconfig@5.2.1: - dependencies: - import-fresh: 2.0.0 - is-directory: 0.3.1 - js-yaml: 4.1.1 - parse-json: 4.0.0 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - crypto-random-string@2.0.0: {} - - csstype@3.1.3: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - - debug@3.2.7: - dependencies: - ms: 2.1.3 - - debug@4.4.1: - dependencies: - ms: 2.1.3 - - decode-uri-component@0.2.2: {} - - deep-extend@0.6.0: {} - - deepmerge@4.3.1: {} - - defaults@1.0.4: - dependencies: - clone: 1.0.4 - - define-lazy-prop@2.0.0: {} - - depd@2.0.0: {} - - destroy@1.2.0: {} - - detect-libc@1.0.3: {} - - dotenv-expand@11.0.7: - dependencies: - dotenv: 16.4.7 - - dotenv@16.4.7: {} - - eastasianwidth@0.2.0: {} - - ee-first@1.1.1: {} - - electron-to-chromium@1.5.214: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - encodeurl@1.0.2: {} - - encodeurl@2.0.0: {} - - env-editor@0.4.2: {} - - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - - error-stack-parser@2.1.4: - dependencies: - stackframe: 1.3.4 - - escalade@3.2.0: {} - - escape-html@1.0.3: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@2.0.0: {} - - escape-string-regexp@4.0.0: {} - - etag@1.8.1: {} - - event-target-shim@5.0.1: {} - - exec-async@2.2.0: {} - - expo-apple-authentication@7.2.4(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - expo-asset@11.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - '@expo/image-utils': 0.7.6 - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-constants: 17.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - transitivePeerDependencies: - - supports-color - - expo-blur@14.1.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - expo-clipboard@7.1.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - expo-constants@17.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)): - dependencies: - '@expo/config': 11.0.13 - '@expo/env': 1.0.7 - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - transitivePeerDependencies: - - supports-color - - expo-crypto@14.1.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)): - dependencies: - base64-js: 1.5.1 - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - - expo-document-picker@13.1.6(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - - expo-file-system@18.1.11(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - expo-font@13.3.2(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - fontfaceobserver: 2.3.0 - react: 19.0.0 - - expo-haptics@14.1.4(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - - expo-image@2.2.1(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - expo-keep-awake@14.1.4(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react: 19.0.0 - - expo-linking@7.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - expo-constants: 17.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - invariant: 2.2.4 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - transitivePeerDependencies: - - expo - - supports-color - - expo-modules-autolinking@2.1.14: - dependencies: - '@expo/spawn-async': 1.7.2 - chalk: 4.1.2 - commander: 7.2.0 - find-up: 5.0.0 - glob: 12.0.0 - require-from-string: 2.0.2 - resolve-from: 5.0.0 - - expo-modules-core@2.5.0: - dependencies: - invariant: 2.2.4 - - expo-router@5.0.7(6ef5553abe53fc2c54fd463e8e887e39): - dependencies: - '@expo/metro-runtime': 5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - '@expo/server': 0.6.3 - '@radix-ui/react-slot': 1.2.0(@types/react@19.0.14)(react@19.0.0) - '@react-navigation/bottom-tabs': 7.4.7(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-screens@4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - '@react-navigation/native': 7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - '@react-navigation/native-stack': 7.3.26(@react-navigation/native@7.1.17(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native-screens@4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - client-only: 0.0.1 - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-constants: 17.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - expo-linking: 7.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - invariant: 2.2.4 - react-fast-compare: 3.2.2 - react-native-is-edge-to-edge: 1.2.1(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-safe-area-context: 5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-screens: 4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - schema-utils: 4.3.2 - semver: 7.6.3 - server-only: 0.0.1 - shallowequal: 1.1.0 - optionalDependencies: - react-native-reanimated: 3.17.5(@babel/core@7.28.3)(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - transitivePeerDependencies: - - '@react-native-masked-view/masked-view' - - '@types/react' - - react - - react-native - - supports-color - - expo-sharing@13.1.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - - expo-splash-screen@0.30.10(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0)): - dependencies: - '@expo/prebuild-config': 9.0.11 - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - transitivePeerDependencies: - - supports-color - - expo-status-bar@2.2.3(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - react-native-edge-to-edge: 1.6.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native-is-edge-to-edge: 1.2.1(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - - expo-symbols@0.4.5(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - sf-symbols-typescript: 2.1.0 - - expo-system-ui@5.0.10(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)): - dependencies: - '@react-native/normalize-colors': 0.79.5 - debug: 4.4.1 - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - transitivePeerDependencies: - - supports-color - - expo-web-browser@14.1.6(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)): - dependencies: - expo: 53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.28.3 - '@expo/cli': 0.24.21 - '@expo/config': 11.0.13 - '@expo/config-plugins': 10.1.2 - '@expo/fingerprint': 0.13.4 - '@expo/metro-config': 0.20.17 - '@expo/vector-icons': 14.1.0(expo-font@13.3.2(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - babel-preset-expo: 13.2.4(@babel/core@7.28.3) - expo-asset: 11.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - expo-constants: 17.1.7(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - expo-file-system: 18.1.11(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - expo-font: 13.3.2(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0) - expo-keep-awake: 14.1.4(expo@53.0.22(@babel/core@7.28.3)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)))(react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0))(react@19.0.0) - expo-modules-autolinking: 2.1.14 - expo-modules-core: 2.5.0 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - react-native-edge-to-edge: 1.6.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - whatwg-url-without-unicode: 8.0.0-3 - optionalDependencies: - '@expo/metro-runtime': 5.0.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0)) - react-native-webview: 13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-react-compiler - - bufferutil - - graphql - - supports-color - - utf-8-validate - - exponential-backoff@3.1.2: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-uri@3.1.0: {} - - fb-watchman@2.0.2: - dependencies: - bser: 2.1.1 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - filter-obj@1.1.0: {} - - finalhandler@1.1.2: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.5.0 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flow-enums-runtime@0.0.6: {} - - fontfaceobserver@2.3.0: {} - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - freeport-async@2.0.0: {} - - fresh@0.5.2: {} - - fs.realpath@1.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-package-type@0.1.0: {} - - getenv@2.0.0: {} - - glob@12.0.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 4.1.1 - minimatch: 10.1.1 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.1 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - graceful-fs@4.2.11: {} - - has-flag@3.0.0: {} - - has-flag@4.0.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - hermes-estree@0.25.1: {} - - hermes-estree@0.29.1: {} - - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 - - hermes-parser@0.29.1: - dependencies: - hermes-estree: 0.29.1 - - hoist-non-react-statics@3.3.2: - dependencies: - react-is: 16.13.1 - - hosted-git-info@7.0.2: - dependencies: - lru-cache: 10.4.3 - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - image-size@1.2.1: - dependencies: - queue: 6.0.2 - - import-fresh@2.0.0: - dependencies: - caller-path: 2.0.0 - resolve-from: 3.0.0 - - imurmurhash@0.1.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ini@1.3.8: {} - - invariant@2.2.4: - dependencies: - loose-envify: 1.4.0 - - is-arrayish@0.2.1: {} - - is-arrayish@0.3.2: {} - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-directory@0.3.1: {} - - is-docker@2.2.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-number@7.0.0: {} - - is-plain-obj@2.1.0: {} - - is-wsl@2.2.0: - dependencies: - is-docker: 2.2.1 - - isexe@2.0.0: {} - - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-instrument@5.2.1: - dependencies: - '@babel/core': 7.28.3 - '@babel/parser': 7.28.3 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - jackspeak@4.1.1: - dependencies: - '@isaacs/cliui': 8.0.2 - - jest-environment-node@29.7.0: - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.1 - jest-mock: 29.7.0 - jest-util: 29.7.0 - - jest-get-type@29.6.3: {} - - jest-haste-map@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 - '@types/node': 22.18.1 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.8 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - - jest-message-util@29.7.0: - dependencies: - '@babel/code-frame': 7.27.1 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.3 - chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 - - jest-mock@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 22.18.1 - jest-util: 29.7.0 - - jest-regex-util@29.6.3: {} - - jest-util@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 22.18.1 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - - jest-validate@29.7.0: - dependencies: - '@jest/types': 29.6.3 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 29.6.3 - leven: 3.1.0 - pretty-format: 29.7.0 - - jest-worker@29.7.0: - dependencies: - '@types/node': 22.18.1 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - jimp-compact@0.16.1: {} - - js-tokens@4.0.0: {} - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - jsc-safe-url@0.2.4: {} - - jsesc@3.0.2: {} - - jsesc@3.1.0: {} - - json-parse-better-errors@1.0.2: {} - - json-schema-traverse@1.0.0: {} - - json5@2.2.3: {} - - kleur@3.0.3: {} - - lan-network@0.1.7: {} - - leven@3.1.0: {} - - lighthouse-logger@1.4.2: - dependencies: - debug: 2.6.9 - marky: 1.3.0 - transitivePeerDependencies: - - supports-color - - lightningcss-darwin-arm64@1.27.0: - optional: true - - lightningcss-darwin-x64@1.27.0: - optional: true - - lightningcss-freebsd-x64@1.27.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.27.0: - optional: true - - lightningcss-linux-arm64-gnu@1.27.0: - optional: true - - lightningcss-linux-arm64-musl@1.27.0: - optional: true - - lightningcss-linux-x64-gnu@1.27.0: - optional: true - - lightningcss-linux-x64-musl@1.27.0: - optional: true - - lightningcss-win32-arm64-msvc@1.27.0: - optional: true - - lightningcss-win32-x64-msvc@1.27.0: - optional: true - - lightningcss@1.27.0: - dependencies: - detect-libc: 1.0.3 - optionalDependencies: - lightningcss-darwin-arm64: 1.27.0 - lightningcss-darwin-x64: 1.27.0 - lightningcss-freebsd-x64: 1.27.0 - lightningcss-linux-arm-gnueabihf: 1.27.0 - lightningcss-linux-arm64-gnu: 1.27.0 - lightningcss-linux-arm64-musl: 1.27.0 - lightningcss-linux-x64-gnu: 1.27.0 - lightningcss-linux-x64-musl: 1.27.0 - lightningcss-win32-arm64-msvc: 1.27.0 - lightningcss-win32-x64-msvc: 1.27.0 - - lines-and-columns@1.2.4: {} - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.debounce@4.0.8: {} - - lodash.throttle@4.1.1: {} - - log-symbols@2.2.0: - dependencies: - chalk: 2.4.2 - - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - - lru-cache@10.4.3: {} - - lru-cache@11.2.2: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - makeerror@1.0.12: - dependencies: - tmpl: 1.0.5 - - marky@1.3.0: {} - - memoize-one@5.2.1: {} - - merge-options@3.0.4: - dependencies: - is-plain-obj: 2.1.0 - - merge-stream@2.0.0: {} - - metro-babel-transformer@0.82.5: - dependencies: - '@babel/core': 7.28.3 - flow-enums-runtime: 0.0.6 - hermes-parser: 0.29.1 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - - metro-cache-key@0.82.5: - dependencies: - flow-enums-runtime: 0.0.6 - - metro-cache@0.82.5: - dependencies: - exponential-backoff: 3.1.2 - flow-enums-runtime: 0.0.6 - https-proxy-agent: 7.0.6 - metro-core: 0.82.5 - transitivePeerDependencies: - - supports-color - - metro-config@0.82.5: - dependencies: - connect: 3.7.0 - cosmiconfig: 5.2.1 - flow-enums-runtime: 0.0.6 - jest-validate: 29.7.0 - metro: 0.82.5 - metro-cache: 0.82.5 - metro-core: 0.82.5 - metro-runtime: 0.82.5 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - metro-core@0.82.5: - dependencies: - flow-enums-runtime: 0.0.6 - lodash.throttle: 4.1.1 - metro-resolver: 0.82.5 - - metro-file-map@0.82.5: - dependencies: - debug: 4.4.1 - fb-watchman: 2.0.2 - flow-enums-runtime: 0.0.6 - graceful-fs: 4.2.11 - invariant: 2.2.4 - jest-worker: 29.7.0 - micromatch: 4.0.8 - nullthrows: 1.1.1 - walker: 1.0.8 - transitivePeerDependencies: - - supports-color - - metro-minify-terser@0.82.5: - dependencies: - flow-enums-runtime: 0.0.6 - terser: 5.44.0 - - metro-resolver@0.82.5: - dependencies: - flow-enums-runtime: 0.0.6 - - metro-runtime@0.82.5: - dependencies: - '@babel/runtime': 7.28.3 - flow-enums-runtime: 0.0.6 - - metro-source-map@0.82.5: - dependencies: - '@babel/traverse': 7.28.3 - '@babel/traverse--for-generate-function-map': '@babel/traverse@7.28.3' - '@babel/types': 7.28.2 - flow-enums-runtime: 0.0.6 - invariant: 2.2.4 - metro-symbolicate: 0.82.5 - nullthrows: 1.1.1 - ob1: 0.82.5 - source-map: 0.5.7 - vlq: 1.0.1 - transitivePeerDependencies: - - supports-color - - metro-symbolicate@0.82.5: - dependencies: - flow-enums-runtime: 0.0.6 - invariant: 2.2.4 - metro-source-map: 0.82.5 - nullthrows: 1.1.1 - source-map: 0.5.7 - vlq: 1.0.1 - transitivePeerDependencies: - - supports-color - - metro-transform-plugins@0.82.5: - dependencies: - '@babel/core': 7.28.3 - '@babel/generator': 7.28.3 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - flow-enums-runtime: 0.0.6 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - - metro-transform-worker@0.82.5: - dependencies: - '@babel/core': 7.28.3 - '@babel/generator': 7.28.3 - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - flow-enums-runtime: 0.0.6 - metro: 0.82.5 - metro-babel-transformer: 0.82.5 - metro-cache: 0.82.5 - metro-cache-key: 0.82.5 - metro-minify-terser: 0.82.5 - metro-source-map: 0.82.5 - metro-transform-plugins: 0.82.5 - nullthrows: 1.1.1 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - metro@0.82.5: - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/core': 7.28.3 - '@babel/generator': 7.28.3 - '@babel/parser': 7.28.3 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - accepts: 1.3.8 - chalk: 4.1.2 - ci-info: 2.0.0 - connect: 3.7.0 - debug: 4.4.1 - error-stack-parser: 2.1.4 - flow-enums-runtime: 0.0.6 - graceful-fs: 4.2.11 - hermes-parser: 0.29.1 - image-size: 1.2.1 - invariant: 2.2.4 - jest-worker: 29.7.0 - jsc-safe-url: 0.2.4 - lodash.throttle: 4.1.1 - metro-babel-transformer: 0.82.5 - metro-cache: 0.82.5 - metro-cache-key: 0.82.5 - metro-config: 0.82.5 - metro-core: 0.82.5 - metro-file-map: 0.82.5 - metro-resolver: 0.82.5 - metro-runtime: 0.82.5 - metro-source-map: 0.82.5 - metro-symbolicate: 0.82.5 - metro-transform-plugins: 0.82.5 - metro-transform-worker: 0.82.5 - mime-types: 2.1.35 - nullthrows: 1.1.1 - serialize-error: 2.1.0 - source-map: 0.5.7 - throat: 5.0.0 - ws: 7.5.10 - yargs: 17.7.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mime-db@1.52.0: {} - - mime-db@1.54.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@1.6.0: {} - - mimic-fn@1.2.0: {} - - minimatch@10.1.1: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.12 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 - - minimist@1.2.8: {} - - minipass@7.1.2: {} - - minizlib@3.0.2: - dependencies: - minipass: 7.1.2 - - mkdirp@1.0.4: {} - - mkdirp@3.0.1: {} - - ms@2.0.0: {} - - ms@2.1.3: {} - - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - - nanoid@3.3.11: {} - - negotiator@0.6.3: {} - - negotiator@0.6.4: {} - - nested-error-stacks@2.0.1: {} - - node-forge@1.3.1: {} - - node-int64@0.4.0: {} - - node-releases@2.0.19: {} - - normalize-path@3.0.0: {} - - npm-package-arg@11.0.3: - dependencies: - hosted-git-info: 7.0.2 - proc-log: 4.2.0 - semver: 7.7.2 - validate-npm-package-name: 5.0.1 - - nullthrows@1.1.1: {} - - ob1@0.82.5: - dependencies: - flow-enums-runtime: 0.0.6 - - object-assign@4.1.1: {} - - on-finished@2.3.0: - dependencies: - ee-first: 1.1.1 - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - on-headers@1.1.0: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@2.0.1: - dependencies: - mimic-fn: 1.2.0 - - open@7.4.2: - dependencies: - is-docker: 2.2.1 - is-wsl: 2.2.0 - - open@8.4.2: - dependencies: - define-lazy-prop: 2.0.0 - is-docker: 2.2.1 - is-wsl: 2.2.0 - - ora@3.4.0: - dependencies: - chalk: 2.4.2 - cli-cursor: 2.1.0 - cli-spinners: 2.9.2 - log-symbols: 2.2.0 - strip-ansi: 5.2.0 - wcwidth: 1.0.1 - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-try@2.2.0: {} - - package-json-from-dist@1.0.1: {} - - parse-json@4.0.0: - dependencies: - error-ex: 1.3.2 - json-parse-better-errors: 1.0.2 - - parse-png@2.1.0: - dependencies: - pngjs: 3.4.0 - - parseurl@1.3.3: {} - - path-exists@4.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - path-scurry@2.0.1: - dependencies: - lru-cache: 11.2.2 - minipass: 7.1.2 - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@3.0.1: {} - - pirates@4.0.7: {} - - plist@3.1.0: - dependencies: - '@xmldom/xmldom': 0.8.11 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - - pngjs@3.4.0: {} - - postcss@8.4.49: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - pretty-bytes@5.6.0: {} - - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - proc-log@4.2.0: {} - - progress@2.0.3: {} - - promise@8.3.0: - dependencies: - asap: 2.0.6 - - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - - punycode@2.3.1: {} - - qrcode-terminal@0.11.0: {} - - query-string@7.1.3: - dependencies: - decode-uri-component: 0.2.2 - filter-obj: 1.1.0 - split-on-first: 1.1.0 - strict-uri-encode: 2.0.0 - - queue@6.0.2: - dependencies: - inherits: 2.0.4 - - range-parser@1.2.1: {} - - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - - react-devtools-core@6.1.5: - dependencies: - shell-quote: 1.8.3 - ws: 7.5.10 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - react-fast-compare@3.2.2: {} - - react-freeze@1.0.4(react@19.0.0): - dependencies: - react: 19.0.0 - - react-is@16.13.1: {} - - react-is@18.3.1: {} - - react-is@19.1.1: {} - - react-native-edge-to-edge@1.6.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - react-native-gesture-handler@2.24.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - '@egjs/hammerjs': 2.0.17 - hoist-non-react-statics: 3.3.2 - invariant: 2.2.4 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - react-native-is-edge-to-edge@1.1.7(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - react-native-is-edge-to-edge@1.2.1(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - react-native-reanimated@3.17.5(@babel/core@7.28.3)(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-classes': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.3) - '@babel/preset-typescript': 7.27.1(@babel/core@7.28.3) - convert-source-map: 2.0.0 - invariant: 2.2.4 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - react-native-is-edge-to-edge: 1.1.7(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - transitivePeerDependencies: - - supports-color - - react-native-safe-area-context@5.4.0(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - react-native-screens@4.15.4(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - react: 19.0.0 - react-freeze: 1.0.4(react@19.0.0) - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - react-native-is-edge-to-edge: 1.2.1(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - warn-once: 0.1.1 - - react-native-webview@13.13.5(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0): - dependencies: - escape-string-regexp: 4.0.0 - invariant: 2.2.4 - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0) - - react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0): - dependencies: - '@jest/create-cache-key-function': 29.7.0 - '@react-native/assets-registry': 0.79.3 - '@react-native/codegen': 0.79.3(@babel/core@7.28.3) - '@react-native/community-cli-plugin': 0.79.3 - '@react-native/gradle-plugin': 0.79.3 - '@react-native/js-polyfills': 0.79.3 - '@react-native/normalize-colors': 0.79.3 - '@react-native/virtualized-lists': 0.79.3(@types/react@19.0.14)(react-native@0.79.3(@babel/core@7.28.3)(@types/react@19.0.14)(react@19.0.0))(react@19.0.0) - abort-controller: 3.0.0 - anser: 1.4.10 - ansi-regex: 5.0.1 - babel-jest: 29.7.0(@babel/core@7.28.3) - babel-plugin-syntax-hermes-parser: 0.25.1 - base64-js: 1.5.1 - chalk: 4.1.2 - commander: 12.1.0 - event-target-shim: 5.0.1 - flow-enums-runtime: 0.0.6 - glob: 7.2.3 - invariant: 2.2.4 - jest-environment-node: 29.7.0 - memoize-one: 5.2.1 - metro-runtime: 0.82.5 - metro-source-map: 0.82.5 - nullthrows: 1.1.1 - pretty-format: 29.7.0 - promise: 8.3.0 - react: 19.0.0 - react-devtools-core: 6.1.5 - react-refresh: 0.14.2 - regenerator-runtime: 0.13.11 - scheduler: 0.25.0 - semver: 7.7.2 - stacktrace-parser: 0.1.11 - whatwg-fetch: 3.6.20 - ws: 6.2.3 - yargs: 17.7.2 - optionalDependencies: - '@types/react': 19.0.14 - transitivePeerDependencies: - - '@babel/core' - - '@react-native-community/cli' - - bufferutil - - supports-color - - utf-8-validate - - react-refresh@0.14.2: {} - - react@19.0.0: {} - - regenerate-unicode-properties@10.2.0: - dependencies: - regenerate: 1.4.2 - - regenerate@1.4.2: {} - - regenerator-runtime@0.13.11: {} - - regexpu-core@6.2.0: - dependencies: - regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.0 - regjsgen: 0.8.0 - regjsparser: 0.12.0 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.0 - - regjsgen@0.8.0: {} - - regjsparser@0.12.0: - dependencies: - jsesc: 3.0.2 - - require-directory@2.1.1: {} - - require-from-string@2.0.2: {} - - requireg@0.2.2: - dependencies: - nested-error-stacks: 2.0.1 - rc: 1.2.8 - resolve: 1.7.1 - - resolve-from@3.0.0: {} - - resolve-from@5.0.0: {} - - resolve-workspace-root@2.0.0: {} - - resolve.exports@2.0.3: {} - - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - resolve@1.7.1: - dependencies: - path-parse: 1.0.7 - - restore-cursor@2.0.0: - dependencies: - onetime: 2.0.1 - signal-exit: 3.0.7 - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - safe-buffer@5.2.1: {} - - sax@1.4.1: {} - - scheduler@0.25.0: {} - - schema-utils@4.3.2: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) - - semver@6.3.1: {} - - semver@7.6.3: {} - - semver@7.7.2: {} - - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - send@0.19.1: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - serialize-error@2.1.0: {} - - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - - server-only@0.0.1: {} - - setprototypeof@1.2.0: {} - - sf-symbols-typescript@2.1.0: {} - - shallowequal@1.1.0: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - shell-quote@1.8.3: {} - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - simple-plist@1.3.1: - dependencies: - bplist-creator: 0.1.0 - bplist-parser: 0.3.1 - plist: 3.1.0 - - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - - sisteransi@1.0.5: {} - - slash@3.0.0: {} - - slugify@1.6.6: {} - - source-map-js@1.2.1: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.5.7: {} - - source-map@0.6.1: {} - - split-on-first@1.1.0: {} - - stack-utils@2.0.6: - dependencies: - escape-string-regexp: 2.0.0 - - stackframe@1.3.4: {} - - stacktrace-parser@0.1.11: - dependencies: - type-fest: 0.7.1 - - statuses@1.5.0: {} - - statuses@2.0.1: {} - - stream-buffers@2.2.0: {} - - strict-uri-encode@2.0.0: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - strip-ansi@5.2.0: - dependencies: - ansi-regex: 4.1.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.2.0 - - strip-json-comments@2.0.1: {} - - structured-headers@0.4.1: {} - - sucrase@3.35.0: - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - commander: 4.1.1 - glob: 12.0.0 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.7 - ts-interface-checker: 0.1.13 - - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - supports-hyperlinks@2.3.0: - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - tar@7.4.3: - dependencies: - '@isaacs/fs-minipass': 4.0.1 - chownr: 3.0.0 - minipass: 7.1.2 - minizlib: 3.0.2 - mkdirp: 3.0.1 - yallist: 5.0.0 - - temp-dir@2.0.0: {} - - terminal-link@2.1.1: - dependencies: - ansi-escapes: 4.3.2 - supports-hyperlinks: 2.3.0 - - terser@5.44.0: - dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 - commander: 2.20.3 - source-map-support: 0.5.21 - - test-exclude@6.0.0: - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - - throat@5.0.0: {} - - tmpl@1.0.5: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - toidentifier@1.0.1: {} - - ts-interface-checker@0.1.13: {} - - type-detect@4.0.8: {} - - type-fest@0.21.3: {} - - type-fest@0.7.1: {} - - undici-types@6.21.0: {} - - undici@6.21.3: {} - - undici@7.15.0: {} - - unicode-canonical-property-names-ecmascript@2.0.1: {} - - unicode-match-property-ecmascript@2.0.0: - dependencies: - unicode-canonical-property-names-ecmascript: 2.0.1 - unicode-property-aliases-ecmascript: 2.1.0 - - unicode-match-property-value-ecmascript@2.2.0: {} - - unicode-property-aliases-ecmascript@2.1.0: {} - - unique-string@2.0.0: - dependencies: - crypto-random-string: 2.0.0 - - unpipe@1.0.0: {} - - update-browserslist-db@1.1.3(browserslist@4.25.4): - dependencies: - browserslist: 4.25.4 - escalade: 3.2.0 - picocolors: 1.1.1 - - use-latest-callback@0.2.4(react@19.0.0): - dependencies: - react: 19.0.0 - - use-sync-external-store@1.5.0(react@19.0.0): - dependencies: - react: 19.0.0 - - utils-merge@1.0.1: {} - - uuid@7.0.3: {} - - validate-npm-package-name@5.0.1: {} - - vary@1.1.2: {} - - vlq@1.0.1: {} - - walker@1.0.8: - dependencies: - makeerror: 1.0.12 - - warn-once@0.1.1: {} - - wcwidth@1.0.1: - dependencies: - defaults: 1.0.4 - - webidl-conversions@5.0.0: {} - - whatwg-fetch@3.6.20: {} - - whatwg-url-without-unicode@8.0.0-3: - dependencies: - buffer: 5.7.1 - punycode: 2.3.1 - webidl-conversions: 5.0.0 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - wonka@6.3.5: {} - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - wrappy@1.0.2: {} - - write-file-atomic@4.0.2: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - - ws@6.2.3: - dependencies: - async-limiter: 1.0.1 - - ws@7.5.10: {} - - ws@8.18.3: {} - - xcode@3.0.1: - dependencies: - simple-plist: 1.3.1 - uuid: 7.0.3 - - xml2js@0.6.0: - dependencies: - sax: 1.4.1 - xmlbuilder: 11.0.1 - - xmlbuilder@11.0.1: {} - - xmlbuilder@15.1.1: {} - - y18n@5.0.8: {} - - yallist@3.1.1: {} - - yallist@5.0.0: {} - - yargs-parser@21.1.1: {} - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yocto-queue@0.1.0: {} diff --git a/examples/demos/ReactNativeDemo/tsconfig.json b/examples/demos/ReactNativeDemo/tsconfig.json deleted file mode 100644 index 092deabf0..000000000 --- a/examples/demos/ReactNativeDemo/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": [ - "expo/tsconfig.base", - "../../../build/configs/tsconfig/base.json" - ], - "compilerOptions": { - "paths": { - "@/*": ["./*"] - }, - /* Override specific settings from base.json as needed for React Native */ - "lib": ["ESNext"], - "jsx": "react-native" - }, - "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"] -} diff --git a/examples/demos/backend/.gitignore b/examples/demos/backend/.gitignore deleted file mode 100644 index 5d1bff8da..000000000 --- a/examples/demos/backend/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.nhost -.secrets diff --git a/examples/demos/backend/.secrets.example b/examples/demos/backend/.secrets.example deleted file mode 100644 index 9b220abe2..000000000 --- a/examples/demos/backend/.secrets.example +++ /dev/null @@ -1,16 +0,0 @@ -GRAFANA_ADMIN_PASSWORD = 'grafana-admin-password' -HASURA_GRAPHQL_ADMIN_SECRET = 'nhost-admin-secret' -HASURA_GRAPHQL_JWT_SECRET = '55b1d038dff8d4f9a440e848250668527fa5b563700be0dc39e356f1c91f867e' -NHOST_WEBHOOK_SECRET = 'nhost-webhook-secret' -GITHUB_CLIENT_ID='fixme' -GITHUB_CLIENT_SECRET='fixme' -APPLE_TEAM_ID='fakeTeamId' -APPLE_CLIENT_ID='host.exp.Exponent' -APPLE_AUDIENCE='host.exp.Exponent' -APPLE_KEY_ID='fakeKeyId' -APPLE_PRIVATE_KEY='''-----BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQglHTWHjauHnKCxjEP -BpMYsTDI2cihQi4tAYHTthj+FF+gCgYIKoZIzj0DAQehRANCAAR30Hs8vTbED10z -Qx2m4sJu+lE/ZJsRvDkqLqYF8uh1Tb1g7/KKr8Y7qkK3DmCg72bCyirEq4NVUi2r -M/6TYMpw ------END PRIVATE KEY-----''' diff --git a/examples/demos/backend/Makefile b/examples/demos/backend/Makefile deleted file mode 100644 index 85bfedcda..000000000 --- a/examples/demos/backend/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -.PHONY: dev-env-up -dev-env-up: - @./env-up.sh - -.PHONY: dev-env-down -dev-env-down: - @nhost down --volumes diff --git a/examples/demos/backend/README.md b/examples/demos/backend/README.md deleted file mode 100644 index 04af0e395..000000000 --- a/examples/demos/backend/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# backend - -This is a very simple Nhost backend that we will use to demonstrate how to use the various SDKs we are experimenting with. The backend will consist of the following: - -## Database schema - -- A `tasks` table with the following columns: - - - `id` (UUID) - - `created_at` (Timestamp) - - `updated_at` (Timestamp) - - `user_id` (foreigh key to `auth.users.id`) - - `title` (Text) - - `description` (Text) - - `completed` (Boolean) - -- An `attachments` table with the following columns: - - `task_id` (foreign key to `tasks.id`) - - `file_id` (foreign key to `storage.files.id`) - -Permissions: - -- `tasks`: the `user` role can insert/select/update tasks that they own. Ownership is tracked by the `user_id` column which is set automatically on insert from the session. -- `attachments`: the `user` role can insert/select/delete attachments for tasks and files that they own -- `storage.files`: the `user` role can insert/select/delete files that they own - -## Functions - -- A `simple` function called `echo` that will just return back some request information diff --git a/examples/demos/backend/env-up.sh b/examples/demos/backend/env-up.sh deleted file mode 100755 index 6ff54ef84..000000000 --- a/examples/demos/backend/env-up.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# if .secrets file doesn't exist, cp .secrets.example .secrets -if [ ! -f .secrets ]; then - cp .secrets.example .secrets -fi - -nhost up diff --git a/examples/demos/backend/functions/package-lock.json b/examples/demos/backend/functions/package-lock.json deleted file mode 100644 index b3a60ffe0..000000000 --- a/examples/demos/backend/functions/package-lock.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "functions", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "functions", - "version": "1.0.0", - "license": "ISC", - "devDependencies": {} - } - } -} diff --git a/examples/demos/backend/functions/package.json b/examples/demos/backend/functions/package.json deleted file mode 100644 index 98ef9bba4..000000000 --- a/examples/demos/backend/functions/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "functions", - "version": "1.0.0", - "description": "", - "main": "index.js", - "devDependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC" -} diff --git a/examples/demos/backend/functions/tsconfig.json b/examples/demos/backend/functions/tsconfig.json deleted file mode 100644 index 0f4467244..000000000 --- a/examples/demos/backend/functions/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "allowJs": true, - "skipLibCheck": true, - "noEmit": true, - "esModuleInterop": true, - "resolveJsonModule": true, - "isolatedModules": true, - "strictNullChecks": false - } -} diff --git a/examples/demos/backend/nhost/config.yaml b/examples/demos/backend/nhost/config.yaml deleted file mode 100644 index 0a70affa4..000000000 --- a/examples/demos/backend/nhost/config.yaml +++ /dev/null @@ -1 +0,0 @@ -version: 3 diff --git a/examples/demos/backend/nhost/emails/bg/email-confirm-change/body.html b/examples/demos/backend/nhost/emails/bg/email-confirm-change/body.html deleted file mode 100644 index 437face7d..000000000 --- a/examples/demos/backend/nhost/emails/bg/email-confirm-change/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Потвърдете смяната на вашия имейл

-

Използвайте посочения линк, за да повърдите смяната на имейл:

- - - - - - -
- Смени имейл -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/bg/email-confirm-change/subject.txt b/examples/demos/backend/nhost/emails/bg/email-confirm-change/subject.txt deleted file mode 100644 index 790147e6c..000000000 --- a/examples/demos/backend/nhost/emails/bg/email-confirm-change/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Потвърждение за смяна на имейл \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/bg/email-verify/body.html b/examples/demos/backend/nhost/emails/bg/email-verify/body.html deleted file mode 100644 index 9a9604f40..000000000 --- a/examples/demos/backend/nhost/emails/bg/email-verify/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Потвърдете вашия имейл

-

Използвайте посочения линк, за да потвърдите вашия имейл:

- - - - - - -
- Потвърдете имейл -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/bg/email-verify/subject.txt b/examples/demos/backend/nhost/emails/bg/email-verify/subject.txt deleted file mode 100644 index f0109ef96..000000000 --- a/examples/demos/backend/nhost/emails/bg/email-verify/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Потвърждаване на имейл \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/bg/password-reset/body.html b/examples/demos/backend/nhost/emails/bg/password-reset/body.html deleted file mode 100644 index d69b734de..000000000 --- a/examples/demos/backend/nhost/emails/bg/password-reset/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Смяна на парола

-

Използвайте посочения линк, за да смените вашата парола:

- - - - - - -
- Смяна на парола -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/bg/password-reset/subject.txt b/examples/demos/backend/nhost/emails/bg/password-reset/subject.txt deleted file mode 100644 index 11b95a290..000000000 --- a/examples/demos/backend/nhost/emails/bg/password-reset/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Смяна на парола \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/bg/signin-otp/body.html b/examples/demos/backend/nhost/emails/bg/signin-otp/body.html deleted file mode 100644 index 2fab88cba..000000000 --- a/examples/demos/backend/nhost/emails/bg/signin-otp/body.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - -
-

One-time Password

-

За да влезете в ${redirectTo}, моля, използвайте следната еднократна парола:

- - - - - - -

${ticket}

-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/bg/signin-otp/subject.txt b/examples/demos/backend/nhost/emails/bg/signin-otp/subject.txt deleted file mode 100644 index ec9e5f7e3..000000000 --- a/examples/demos/backend/nhost/emails/bg/signin-otp/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Еднократна парола за ${redirectTo} diff --git a/examples/demos/backend/nhost/emails/bg/signin-passwordless-sms/body.txt b/examples/demos/backend/nhost/emails/bg/signin-passwordless-sms/body.txt deleted file mode 100644 index ccb34253e..000000000 --- a/examples/demos/backend/nhost/emails/bg/signin-passwordless-sms/body.txt +++ /dev/null @@ -1 +0,0 @@ -Вашият код е ${code}. \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/bg/signin-passwordless/body.html b/examples/demos/backend/nhost/emails/bg/signin-passwordless/body.html deleted file mode 100644 index 8d4b40cd2..000000000 --- a/examples/demos/backend/nhost/emails/bg/signin-passwordless/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Магически линк за вход

-

Използвайте посочения линк за защитен и бърз вход:

- - - - - - -
- Вход -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/bg/signin-passwordless/subject.txt b/examples/demos/backend/nhost/emails/bg/signin-passwordless/subject.txt deleted file mode 100644 index 945efccb7..000000000 --- a/examples/demos/backend/nhost/emails/bg/signin-passwordless/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Магически линк за вход \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/cs/email-confirm-change/body.html b/examples/demos/backend/nhost/emails/cs/email-confirm-change/body.html deleted file mode 100644 index b2b4da445..000000000 --- a/examples/demos/backend/nhost/emails/cs/email-confirm-change/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Potvrzení změny emailové adresy

-

Použijte tento odkaz k potvrzení změny emailové adresy:

- - - - - - -
- Změnit email -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/cs/email-confirm-change/subject.txt b/examples/demos/backend/nhost/emails/cs/email-confirm-change/subject.txt deleted file mode 100644 index 52b99137e..000000000 --- a/examples/demos/backend/nhost/emails/cs/email-confirm-change/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Změna vaší emailové adresy \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/cs/email-verify/body.html b/examples/demos/backend/nhost/emails/cs/email-verify/body.html deleted file mode 100644 index 22671ba22..000000000 --- a/examples/demos/backend/nhost/emails/cs/email-verify/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Ověření emailové adresy

-

Použijte tento odkaz k ověření vaší emailové adresy:

- - - - - - -
- Ověřit emailovou adresu -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/cs/email-verify/subject.txt b/examples/demos/backend/nhost/emails/cs/email-verify/subject.txt deleted file mode 100644 index 8e3eabacf..000000000 --- a/examples/demos/backend/nhost/emails/cs/email-verify/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Ověření vaší emailové adresy \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/cs/password-reset/body.html b/examples/demos/backend/nhost/emails/cs/password-reset/body.html deleted file mode 100644 index 3a3fa1d97..000000000 --- a/examples/demos/backend/nhost/emails/cs/password-reset/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Obnova hesla

-

Použijte tento odkaz k obnovení vašeho hesla:

- - - - - - -
- Obnova hesla -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/cs/password-reset/subject.txt b/examples/demos/backend/nhost/emails/cs/password-reset/subject.txt deleted file mode 100644 index 7b8fba50b..000000000 --- a/examples/demos/backend/nhost/emails/cs/password-reset/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Obnova hesla \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/cs/signin-otp/body.html b/examples/demos/backend/nhost/emails/cs/signin-otp/body.html deleted file mode 100644 index 20115716a..000000000 --- a/examples/demos/backend/nhost/emails/cs/signin-otp/body.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - -
-

One-time Password

-

Pro přihlášení do ${redirectTo}, prosím, použijte následující jednorázové heslo:

- - - - - - -

${ticket}

-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/cs/signin-otp/subject.txt b/examples/demos/backend/nhost/emails/cs/signin-otp/subject.txt deleted file mode 100644 index e2cd8c1da..000000000 --- a/examples/demos/backend/nhost/emails/cs/signin-otp/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Jednorázové heslo pro ${redirectTo} diff --git a/examples/demos/backend/nhost/emails/cs/signin-passwordless-sms/body.txt b/examples/demos/backend/nhost/emails/cs/signin-passwordless-sms/body.txt deleted file mode 100644 index df330b769..000000000 --- a/examples/demos/backend/nhost/emails/cs/signin-passwordless-sms/body.txt +++ /dev/null @@ -1 +0,0 @@ -Váš kód je ${code}. \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/cs/signin-passwordless/body.html b/examples/demos/backend/nhost/emails/cs/signin-passwordless/body.html deleted file mode 100644 index f6f019747..000000000 --- a/examples/demos/backend/nhost/emails/cs/signin-passwordless/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Magický odkaz

-

Použijte tento odkaz k bezpečnému přihlášení:

- - - - - - -
- Přihlášení -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/cs/signin-passwordless/subject.txt b/examples/demos/backend/nhost/emails/cs/signin-passwordless/subject.txt deleted file mode 100644 index 8d9a66a25..000000000 --- a/examples/demos/backend/nhost/emails/cs/signin-passwordless/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Bezpečný odkaz k přihlášení \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/en/email-confirm-change/body.html b/examples/demos/backend/nhost/emails/en/email-confirm-change/body.html deleted file mode 100644 index 68034c566..000000000 --- a/examples/demos/backend/nhost/emails/en/email-confirm-change/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Confirm Email Change

-

Use this link to confirm changing email:

- - - - - - -
- Change Email -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/en/email-confirm-change/subject.txt b/examples/demos/backend/nhost/emails/en/email-confirm-change/subject.txt deleted file mode 100644 index 1711dad88..000000000 --- a/examples/demos/backend/nhost/emails/en/email-confirm-change/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Change your email address \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/en/email-verify/body.html b/examples/demos/backend/nhost/emails/en/email-verify/body.html deleted file mode 100644 index e98e013ab..000000000 --- a/examples/demos/backend/nhost/emails/en/email-verify/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Verify Email

-

Use this link to verify your email:

- - - - - - -
- Verify Email -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/en/email-verify/subject.txt b/examples/demos/backend/nhost/emails/en/email-verify/subject.txt deleted file mode 100644 index ef490a8bc..000000000 --- a/examples/demos/backend/nhost/emails/en/email-verify/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Verify your email \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/en/password-reset/body.html b/examples/demos/backend/nhost/emails/en/password-reset/body.html deleted file mode 100644 index bd3b5b483..000000000 --- a/examples/demos/backend/nhost/emails/en/password-reset/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Reset Password

-

Use this link to reset your password:

- - - - - - -
- Reset Password -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/en/password-reset/subject.txt b/examples/demos/backend/nhost/emails/en/password-reset/subject.txt deleted file mode 100644 index e21496754..000000000 --- a/examples/demos/backend/nhost/emails/en/password-reset/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Reset your password \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/en/signin-otp/body.html b/examples/demos/backend/nhost/emails/en/signin-otp/body.html deleted file mode 100644 index 95acc397e..000000000 --- a/examples/demos/backend/nhost/emails/en/signin-otp/body.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - -
-

One-time Password

-

To sign in to ${redirectTo}, please, use the following one-time password:

- - - - - - -

${ticket}

-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/en/signin-otp/subject.txt b/examples/demos/backend/nhost/emails/en/signin-otp/subject.txt deleted file mode 100644 index 3da3fca7f..000000000 --- a/examples/demos/backend/nhost/emails/en/signin-otp/subject.txt +++ /dev/null @@ -1 +0,0 @@ -One-time password for ${redirectTo} diff --git a/examples/demos/backend/nhost/emails/en/signin-passwordless-sms/body.txt b/examples/demos/backend/nhost/emails/en/signin-passwordless-sms/body.txt deleted file mode 100644 index f03ec5b88..000000000 --- a/examples/demos/backend/nhost/emails/en/signin-passwordless-sms/body.txt +++ /dev/null @@ -1 +0,0 @@ -Your code is ${code}. \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/en/signin-passwordless/body.html b/examples/demos/backend/nhost/emails/en/signin-passwordless/body.html deleted file mode 100644 index e8301b5ad..000000000 --- a/examples/demos/backend/nhost/emails/en/signin-passwordless/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Magic Link

-

Use this link to securely sign in:

- - - - - - -
- Magic Link -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/en/signin-passwordless/subject.txt b/examples/demos/backend/nhost/emails/en/signin-passwordless/subject.txt deleted file mode 100644 index 8d0ee0119..000000000 --- a/examples/demos/backend/nhost/emails/en/signin-passwordless/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Secure sign-in link \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/es/email-confirm-change/body.html b/examples/demos/backend/nhost/emails/es/email-confirm-change/body.html deleted file mode 100644 index 5cb7388be..000000000 --- a/examples/demos/backend/nhost/emails/es/email-confirm-change/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Confirmar cambio de correo electrónico

-

Utiliza el siguiente enlace para confirmar el cambio de correo:

- - - - - - -
- Cambiar correo electrónico -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/es/email-confirm-change/subject.txt b/examples/demos/backend/nhost/emails/es/email-confirm-change/subject.txt deleted file mode 100644 index 6a7cf4069..000000000 --- a/examples/demos/backend/nhost/emails/es/email-confirm-change/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Cambiar dirección de correo electrónico \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/es/email-verify/body.html b/examples/demos/backend/nhost/emails/es/email-verify/body.html deleted file mode 100644 index b5b93b813..000000000 --- a/examples/demos/backend/nhost/emails/es/email-verify/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Verificar correo electrónico

-

Utilza el siguiente enlace para verificar tu correo:

- - - - - - -
- Verificar correo electrónico -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/es/email-verify/subject.txt b/examples/demos/backend/nhost/emails/es/email-verify/subject.txt deleted file mode 100644 index cf15cb278..000000000 --- a/examples/demos/backend/nhost/emails/es/email-verify/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Verifica tu correo electrónico \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/es/password-reset/body.html b/examples/demos/backend/nhost/emails/es/password-reset/body.html deleted file mode 100644 index c02bbc800..000000000 --- a/examples/demos/backend/nhost/emails/es/password-reset/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Recuperar contraseña

-

Utiliza el siguiente enlace para recuperar tu contraseña:

- - - - - - -
- Recuperar contraseña -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/es/password-reset/subject.txt b/examples/demos/backend/nhost/emails/es/password-reset/subject.txt deleted file mode 100644 index 417d1c730..000000000 --- a/examples/demos/backend/nhost/emails/es/password-reset/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Recuperar contraseña \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/es/signin-otp/body.html b/examples/demos/backend/nhost/emails/es/signin-otp/body.html deleted file mode 100644 index 3effba1cd..000000000 --- a/examples/demos/backend/nhost/emails/es/signin-otp/body.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - -
-

One-time Password

-

Para iniciar sesión en ${redirectTo}, por favor, utilice la siguiente contraseña de un solo uso:

- - - - - - -

${ticket}

-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/es/signin-otp/subject.txt b/examples/demos/backend/nhost/emails/es/signin-otp/subject.txt deleted file mode 100644 index f041fe0c5..000000000 --- a/examples/demos/backend/nhost/emails/es/signin-otp/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Contraseña de un solo uso para ${redirectTo} diff --git a/examples/demos/backend/nhost/emails/es/signin-passwordless-sms/body.txt b/examples/demos/backend/nhost/emails/es/signin-passwordless-sms/body.txt deleted file mode 100644 index c74950dd2..000000000 --- a/examples/demos/backend/nhost/emails/es/signin-passwordless-sms/body.txt +++ /dev/null @@ -1 +0,0 @@ -Tu código es ${code}. \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/es/signin-passwordless/body.html b/examples/demos/backend/nhost/emails/es/signin-passwordless/body.html deleted file mode 100644 index c1b67a841..000000000 --- a/examples/demos/backend/nhost/emails/es/signin-passwordless/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Enlace mágico

-

Utiliza este enlace para iniciar sesión de forma segura:

- - - - - - -
- Iniciar sesión -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/es/signin-passwordless/subject.txt b/examples/demos/backend/nhost/emails/es/signin-passwordless/subject.txt deleted file mode 100644 index cbd5ab19f..000000000 --- a/examples/demos/backend/nhost/emails/es/signin-passwordless/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Enlace de acceso seguro \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/fr/email-confirm-change/body.html b/examples/demos/backend/nhost/emails/fr/email-confirm-change/body.html deleted file mode 100644 index c4ba00737..000000000 --- a/examples/demos/backend/nhost/emails/fr/email-confirm-change/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Confirmer changement de courriel

-

Utilisez ce lien pour confirmer le changement de courriel:

- - - - - - -
- Changer courriel -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/fr/email-confirm-change/subject.txt b/examples/demos/backend/nhost/emails/fr/email-confirm-change/subject.txt deleted file mode 100644 index 1e12b4b4d..000000000 --- a/examples/demos/backend/nhost/emails/fr/email-confirm-change/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Changez votre adresse courriel diff --git a/examples/demos/backend/nhost/emails/fr/email-verify/body.html b/examples/demos/backend/nhost/emails/fr/email-verify/body.html deleted file mode 100644 index 951c7c7fe..000000000 --- a/examples/demos/backend/nhost/emails/fr/email-verify/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Vérifiez votre courriel

-

Utilisez ce lien pour vérifier votre courriel:

- - - - - - -
- Vérifier courriel -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/fr/email-verify/subject.txt b/examples/demos/backend/nhost/emails/fr/email-verify/subject.txt deleted file mode 100644 index 540cc1800..000000000 --- a/examples/demos/backend/nhost/emails/fr/email-verify/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Vérifier votre courriel diff --git a/examples/demos/backend/nhost/emails/fr/password-reset/body.html b/examples/demos/backend/nhost/emails/fr/password-reset/body.html deleted file mode 100644 index 8dc4da721..000000000 --- a/examples/demos/backend/nhost/emails/fr/password-reset/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Réinitialiser votre mot de passe

-

Utilisez ce lien pour réinitialiser votre mot de passe:

- - - - - - -
- Réinitialiser mot de passe -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/fr/password-reset/subject.txt b/examples/demos/backend/nhost/emails/fr/password-reset/subject.txt deleted file mode 100644 index 5c2caa35b..000000000 --- a/examples/demos/backend/nhost/emails/fr/password-reset/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Réinitialiser votre mot de passe diff --git a/examples/demos/backend/nhost/emails/fr/signin-otp/body.html b/examples/demos/backend/nhost/emails/fr/signin-otp/body.html deleted file mode 100644 index 773e33b83..000000000 --- a/examples/demos/backend/nhost/emails/fr/signin-otp/body.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - -
-

One-time Password

-

Pour vous connecter à ${redirectTo}, veuillez utiliser le mot de passe à usage unique suivant :

- - - - - - -

${ticket}

-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/fr/signin-otp/subject.txt b/examples/demos/backend/nhost/emails/fr/signin-otp/subject.txt deleted file mode 100644 index f4156ed0e..000000000 --- a/examples/demos/backend/nhost/emails/fr/signin-otp/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Mot de passe à usage unique pour ${redirectTo} diff --git a/examples/demos/backend/nhost/emails/fr/signin-passwordless-sms/body.txt b/examples/demos/backend/nhost/emails/fr/signin-passwordless-sms/body.txt deleted file mode 100644 index 72d6ab249..000000000 --- a/examples/demos/backend/nhost/emails/fr/signin-passwordless-sms/body.txt +++ /dev/null @@ -1 +0,0 @@ -Votre code est ${code}. \ No newline at end of file diff --git a/examples/demos/backend/nhost/emails/fr/signin-passwordless/body.html b/examples/demos/backend/nhost/emails/fr/signin-passwordless/body.html deleted file mode 100644 index a45f217bc..000000000 --- a/examples/demos/backend/nhost/emails/fr/signin-passwordless/body.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - -
-

Lien magique

-

Utilisez ce lien pour vous connecter de façon sécurisée:

- - - - - - -
- Connexion -
-
- - - - - - -
- - - - - - - -
Nhost LogoPowered by Nhost
-
-
- - diff --git a/examples/demos/backend/nhost/emails/fr/signin-passwordless/subject.txt b/examples/demos/backend/nhost/emails/fr/signin-passwordless/subject.txt deleted file mode 100644 index dc2d81026..000000000 --- a/examples/demos/backend/nhost/emails/fr/signin-passwordless/subject.txt +++ /dev/null @@ -1 +0,0 @@ -Lien de connexion sécurisé diff --git a/examples/demos/backend/nhost/emails/test/email-verify/body.html b/examples/demos/backend/nhost/emails/test/email-verify/body.html deleted file mode 100644 index 5c2dbc158..000000000 --- a/examples/demos/backend/nhost/emails/test/email-verify/body.html +++ /dev/null @@ -1,8 +0,0 @@ -${link}, -${displayName}, -${email}, -${ticket}, -${redirectTo}, -${serverUrl}, -${clientUrl}, -${locale}, diff --git a/examples/demos/backend/nhost/emails/test/email-verify/subject.txt b/examples/demos/backend/nhost/emails/test/email-verify/subject.txt deleted file mode 100644 index 1fe895365..000000000 --- a/examples/demos/backend/nhost/emails/test/email-verify/subject.txt +++ /dev/null @@ -1 +0,0 @@ -${link}, ${displayName}, ${email}, ${ticket}, ${redirectTo}, ${serverUrl}, ${clientUrl}, ${locale} diff --git a/examples/demos/backend/nhost/metadata/actions.graphql b/examples/demos/backend/nhost/metadata/actions.graphql deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/demos/backend/nhost/metadata/actions.yaml b/examples/demos/backend/nhost/metadata/actions.yaml deleted file mode 100644 index 1edb4c2ff..000000000 --- a/examples/demos/backend/nhost/metadata/actions.yaml +++ /dev/null @@ -1,6 +0,0 @@ -actions: [] -custom_types: - enums: [] - input_objects: [] - objects: [] - scalars: [] diff --git a/examples/demos/backend/nhost/metadata/allow_list.yaml b/examples/demos/backend/nhost/metadata/allow_list.yaml deleted file mode 100644 index fe51488c7..000000000 --- a/examples/demos/backend/nhost/metadata/allow_list.yaml +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/demos/backend/nhost/metadata/api_limits.yaml b/examples/demos/backend/nhost/metadata/api_limits.yaml deleted file mode 100644 index 0967ef424..000000000 --- a/examples/demos/backend/nhost/metadata/api_limits.yaml +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/examples/demos/backend/nhost/metadata/backend_configs.yaml b/examples/demos/backend/nhost/metadata/backend_configs.yaml deleted file mode 100644 index 0967ef424..000000000 --- a/examples/demos/backend/nhost/metadata/backend_configs.yaml +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/examples/demos/backend/nhost/metadata/cron_triggers.yaml b/examples/demos/backend/nhost/metadata/cron_triggers.yaml deleted file mode 100644 index fe51488c7..000000000 --- a/examples/demos/backend/nhost/metadata/cron_triggers.yaml +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/demos/backend/nhost/metadata/databases/databases.yaml b/examples/demos/backend/nhost/metadata/databases/databases.yaml deleted file mode 100644 index 65a11b202..000000000 --- a/examples/demos/backend/nhost/metadata/databases/databases.yaml +++ /dev/null @@ -1,14 +0,0 @@ -- name: default - kind: postgres - configuration: - connection_info: - database_url: - from_env: HASURA_GRAPHQL_DATABASE_URL - isolation_level: read-committed - pool_settings: - connection_lifetime: 600 - idle_timeout: 180 - max_connections: 50 - retries: 1 - use_prepared_statements: true - tables: "!include default/tables/tables.yaml" diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_provider_requests.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_provider_requests.yaml deleted file mode 100644 index 91ba1967d..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_provider_requests.yaml +++ /dev/null @@ -1,23 +0,0 @@ -table: - name: provider_requests - schema: auth -configuration: - column_config: - id: - custom_name: id - options: - custom_name: options - custom_column_names: - id: id - options: options - custom_name: authProviderRequests - custom_root_fields: - delete: deleteAuthProviderRequests - delete_by_pk: deleteAuthProviderRequest - insert: insertAuthProviderRequests - insert_one: insertAuthProviderRequest - select: authProviderRequests - select_aggregate: authProviderRequestsAggregate - select_by_pk: authProviderRequest - update: updateAuthProviderRequests - update_by_pk: updateAuthProviderRequest diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_providers.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_providers.yaml deleted file mode 100644 index 3de528dc9..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_providers.yaml +++ /dev/null @@ -1,28 +0,0 @@ -table: - name: providers - schema: auth -configuration: - column_config: - id: - custom_name: id - custom_column_names: - id: id - custom_name: authProviders - custom_root_fields: - delete: deleteAuthProviders - delete_by_pk: deleteAuthProvider - insert: insertAuthProviders - insert_one: insertAuthProvider - select: authProviders - select_aggregate: authProvidersAggregate - select_by_pk: authProvider - update: updateAuthProviders - update_by_pk: updateAuthProvider -array_relationships: - - name: userProviders - using: - foreign_key_constraint_on: - column: provider_id - table: - name: user_providers - schema: auth diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_refresh_token_types.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_refresh_token_types.yaml deleted file mode 100644 index 8abaa8604..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_refresh_token_types.yaml +++ /dev/null @@ -1,26 +0,0 @@ -table: - name: refresh_token_types - schema: auth -is_enum: true -configuration: - column_config: {} - custom_column_names: {} - custom_name: authRefreshTokenTypes - custom_root_fields: - delete: deleteAuthRefreshTokenTypes - delete_by_pk: deleteAuthRefreshTokenType - insert: insertAuthRefreshTokenTypes - insert_one: insertAuthRefreshTokenType - select: authRefreshTokenTypes - select_aggregate: authRefreshTokenTypesAggregate - select_by_pk: authRefreshTokenType - update: updateAuthRefreshTokenTypes - update_by_pk: updateAuthRefreshTokenType -array_relationships: - - name: refreshTokens - using: - foreign_key_constraint_on: - column: type - table: - name: refresh_tokens - schema: auth diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_refresh_tokens.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_refresh_tokens.yaml deleted file mode 100644 index 2a332c4f2..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_refresh_tokens.yaml +++ /dev/null @@ -1,55 +0,0 @@ -table: - name: refresh_tokens - schema: auth -configuration: - column_config: - created_at: - custom_name: createdAt - expires_at: - custom_name: expiresAt - refresh_token_hash: - custom_name: refreshTokenHash - user_id: - custom_name: userId - custom_column_names: - created_at: createdAt - expires_at: expiresAt - refresh_token_hash: refreshTokenHash - user_id: userId - custom_name: authRefreshTokens - custom_root_fields: - delete: deleteAuthRefreshTokens - delete_by_pk: deleteAuthRefreshToken - insert: insertAuthRefreshTokens - insert_one: insertAuthRefreshToken - select: authRefreshTokens - select_aggregate: authRefreshTokensAggregate - select_by_pk: authRefreshToken - update: updateAuthRefreshTokens - update_by_pk: updateAuthRefreshToken -object_relationships: - - name: user - using: - foreign_key_constraint_on: user_id -select_permissions: - - role: user - permission: - columns: - - id - - created_at - - expires_at - - metadata - - type - - user_id - filter: - user_id: - _eq: X-Hasura-User-Id -delete_permissions: - - role: user - permission: - filter: - _and: - - user_id: - _eq: X-Hasura-User-Id - - type: - _eq: pat diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_roles.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_roles.yaml deleted file mode 100644 index bc6d5a2cf..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_roles.yaml +++ /dev/null @@ -1,35 +0,0 @@ -table: - name: roles - schema: auth -configuration: - column_config: - role: - custom_name: role - custom_column_names: - role: role - custom_name: authRoles - custom_root_fields: - delete: deleteAuthRoles - delete_by_pk: deleteAuthRole - insert: insertAuthRoles - insert_one: insertAuthRole - select: authRoles - select_aggregate: authRolesAggregate - select_by_pk: authRole - update: updateAuthRoles - update_by_pk: updateAuthRole -array_relationships: - - name: userRoles - using: - foreign_key_constraint_on: - column: role - table: - name: user_roles - schema: auth - - name: usersByDefaultRole - using: - foreign_key_constraint_on: - column: default_role - table: - name: users - schema: auth diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_providers.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_providers.yaml deleted file mode 100644 index 02b8eb2da..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_providers.yaml +++ /dev/null @@ -1,48 +0,0 @@ -table: - name: user_providers - schema: auth -configuration: - column_config: - access_token: - custom_name: accessToken - created_at: - custom_name: createdAt - id: - custom_name: id - provider_id: - custom_name: providerId - provider_user_id: - custom_name: providerUserId - refresh_token: - custom_name: refreshToken - updated_at: - custom_name: updatedAt - user_id: - custom_name: userId - custom_column_names: - access_token: accessToken - created_at: createdAt - id: id - provider_id: providerId - provider_user_id: providerUserId - refresh_token: refreshToken - updated_at: updatedAt - user_id: userId - custom_name: authUserProviders - custom_root_fields: - delete: deleteAuthUserProviders - delete_by_pk: deleteAuthUserProvider - insert: insertAuthUserProviders - insert_one: insertAuthUserProvider - select: authUserProviders - select_aggregate: authUserProvidersAggregate - select_by_pk: authUserProvider - update: updateAuthUserProviders - update_by_pk: updateAuthUserProvider -object_relationships: - - name: provider - using: - foreign_key_constraint_on: provider_id - - name: user - using: - foreign_key_constraint_on: user_id diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_roles.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_roles.yaml deleted file mode 100644 index f90553941..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_roles.yaml +++ /dev/null @@ -1,36 +0,0 @@ -table: - name: user_roles - schema: auth -configuration: - column_config: - created_at: - custom_name: createdAt - id: - custom_name: id - role: - custom_name: role - user_id: - custom_name: userId - custom_column_names: - created_at: createdAt - id: id - role: role - user_id: userId - custom_name: authUserRoles - custom_root_fields: - delete: deleteAuthUserRoles - delete_by_pk: deleteAuthUserRole - insert: insertAuthUserRoles - insert_one: insertAuthUserRole - select: authUserRoles - select_aggregate: authUserRolesAggregate - select_by_pk: authUserRole - update: updateAuthUserRoles - update_by_pk: updateAuthUserRole -object_relationships: - - name: roleByRole - using: - foreign_key_constraint_on: role - - name: user - using: - foreign_key_constraint_on: user_id diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_security_keys.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_security_keys.yaml deleted file mode 100644 index 4b432ad67..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_user_security_keys.yaml +++ /dev/null @@ -1,53 +0,0 @@ -table: - name: user_security_keys - schema: auth -configuration: - column_config: - credential_id: - custom_name: credentialId - credential_public_key: - custom_name: credentialPublicKey - id: - custom_name: id - user_id: - custom_name: userId - custom_column_names: - credential_id: credentialId - credential_public_key: credentialPublicKey - id: id - user_id: userId - custom_name: authUserSecurityKeys - custom_root_fields: - delete: deleteAuthUserSecurityKeys - delete_by_pk: deleteAuthUserSecurityKey - insert: insertAuthUserSecurityKeys - insert_one: insertAuthUserSecurityKey - select: authUserSecurityKeys - select_aggregate: authUserSecurityKeysAggregate - select_by_pk: authUserSecurityKey - update: updateAuthUserSecurityKeys - update_by_pk: updateAuthUserSecurityKey -object_relationships: - - name: user - using: - foreign_key_constraint_on: user_id -select_permissions: - - role: user - permission: - columns: - - id - - user_id - - credential_id - - nickname - filter: - user_id: - _eq: X-Hasura-User-Id -update_permissions: - - role: user - permission: - columns: - - nickname - filter: - user_id: - _eq: X-Hasura-User-Id - check: null diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_users.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/auth_users.yaml deleted file mode 100644 index 730001730..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/auth_users.yaml +++ /dev/null @@ -1,122 +0,0 @@ -table: - name: users - schema: auth -configuration: - column_config: - active_mfa_type: - custom_name: activeMfaType - avatar_url: - custom_name: avatarUrl - created_at: - custom_name: createdAt - default_role: - custom_name: defaultRole - disabled: - custom_name: disabled - display_name: - custom_name: displayName - email: - custom_name: email - email_verified: - custom_name: emailVerified - id: - custom_name: id - is_anonymous: - custom_name: isAnonymous - last_seen: - custom_name: lastSeen - locale: - custom_name: locale - new_email: - custom_name: newEmail - otp_hash: - custom_name: otpHash - otp_hash_expires_at: - custom_name: otpHashExpiresAt - otp_method_last_used: - custom_name: otpMethodLastUsed - password_hash: - custom_name: passwordHash - phone_number: - custom_name: phoneNumber - phone_number_verified: - custom_name: phoneNumberVerified - ticket: - custom_name: ticket - ticket_expires_at: - custom_name: ticketExpiresAt - totp_secret: - custom_name: totpSecret - updated_at: - custom_name: updatedAt - webauthn_current_challenge: - custom_name: currentChallenge - custom_column_names: - active_mfa_type: activeMfaType - avatar_url: avatarUrl - created_at: createdAt - default_role: defaultRole - disabled: disabled - display_name: displayName - email: email - email_verified: emailVerified - id: id - is_anonymous: isAnonymous - last_seen: lastSeen - locale: locale - new_email: newEmail - otp_hash: otpHash - otp_hash_expires_at: otpHashExpiresAt - otp_method_last_used: otpMethodLastUsed - password_hash: passwordHash - phone_number: phoneNumber - phone_number_verified: phoneNumberVerified - ticket: ticket - ticket_expires_at: ticketExpiresAt - totp_secret: totpSecret - updated_at: updatedAt - webauthn_current_challenge: currentChallenge - custom_name: users - custom_root_fields: - delete: deleteUsers - delete_by_pk: deleteUser - insert: insertUsers - insert_one: insertUser - select: users - select_aggregate: usersAggregate - select_by_pk: user - update: updateUsers - update_by_pk: updateUser -object_relationships: - - name: defaultRoleByRole - using: - foreign_key_constraint_on: default_role -array_relationships: - - name: refreshTokens - using: - foreign_key_constraint_on: - column: user_id - table: - name: refresh_tokens - schema: auth - - name: roles - using: - foreign_key_constraint_on: - column: user_id - table: - name: user_roles - schema: auth - - name: securityKeys - using: - foreign_key_constraint_on: - column: user_id - table: - name: user_security_keys - schema: auth - - name: userProviders - using: - foreign_key_constraint_on: - column: user_id - table: - name: user_providers - schema: auth diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/public_todos.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/public_todos.yaml deleted file mode 100644 index b66aaa199..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/public_todos.yaml +++ /dev/null @@ -1,47 +0,0 @@ -table: - name: todos - schema: public -insert_permissions: - - role: user - permission: - check: {} - set: - user_id: X-Hasura-User-Id - columns: - - created_at - - updated_at - - title - - details - - completed - - user_id -select_permissions: - - role: user - permission: - columns: - - id - - created_at - - updated_at - - title - - details - - completed - - user_id - filter: - user_id: - _eq: X-Hasura-User-Id -update_permissions: - - role: user - permission: - columns: - - title - - details - - completed - filter: - user_id: - _eq: X-Hasura-User-Id - check: null -delete_permissions: - - role: user - permission: - filter: - user_id: - _eq: X-Hasura-User-Id diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/storage_buckets.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/storage_buckets.yaml deleted file mode 100644 index 12b0e8343..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/storage_buckets.yaml +++ /dev/null @@ -1,49 +0,0 @@ -table: - name: buckets - schema: storage -configuration: - column_config: - cache_control: - custom_name: cacheControl - created_at: - custom_name: createdAt - download_expiration: - custom_name: downloadExpiration - id: - custom_name: id - max_upload_file_size: - custom_name: maxUploadFileSize - min_upload_file_size: - custom_name: minUploadFileSize - presigned_urls_enabled: - custom_name: presignedUrlsEnabled - updated_at: - custom_name: updatedAt - custom_column_names: - cache_control: cacheControl - created_at: createdAt - download_expiration: downloadExpiration - id: id - max_upload_file_size: maxUploadFileSize - min_upload_file_size: minUploadFileSize - presigned_urls_enabled: presignedUrlsEnabled - updated_at: updatedAt - custom_name: buckets - custom_root_fields: - delete: deleteBuckets - delete_by_pk: deleteBucket - insert: insertBuckets - insert_one: insertBucket - select: buckets - select_aggregate: bucketsAggregate - select_by_pk: bucket - update: updateBuckets - update_by_pk: updateBucket -array_relationships: - - name: files - using: - foreign_key_constraint_on: - column: bucket_id - table: - name: files - schema: storage diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/storage_files.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/storage_files.yaml deleted file mode 100644 index 8e2558b36..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/storage_files.yaml +++ /dev/null @@ -1,95 +0,0 @@ -table: - name: files - schema: storage -configuration: - column_config: - bucket_id: - custom_name: bucketId - created_at: - custom_name: createdAt - etag: - custom_name: etag - id: - custom_name: id - is_uploaded: - custom_name: isUploaded - metadata: - custom_name: metadata - mime_type: - custom_name: mimeType - name: - custom_name: name - size: - custom_name: size - updated_at: - custom_name: updatedAt - uploaded_by_user_id: - custom_name: uploadedByUserId - custom_column_names: - bucket_id: bucketId - created_at: createdAt - etag: etag - id: id - is_uploaded: isUploaded - metadata: metadata - mime_type: mimeType - name: name - size: size - updated_at: updatedAt - uploaded_by_user_id: uploadedByUserId - custom_name: files - custom_root_fields: - delete: deleteFiles - delete_by_pk: deleteFile - insert: insertFiles - insert_one: insertFile - select: files - select_aggregate: filesAggregate - select_by_pk: file - update: updateFiles - update_by_pk: updateFile -object_relationships: - - name: bucket - using: - foreign_key_constraint_on: bucket_id -insert_permissions: - - role: user - permission: - check: - bucket_id: - _eq: default - set: - uploaded_by_user_id: X-Hasura-User-Id - columns: - - id - - bucket_id - - name - - size - - mime_type -select_permissions: - - role: user - permission: - columns: - - id - - created_at - - updated_at - - bucket_id - - name - - size - - mime_type - - etag - - is_uploaded - - uploaded_by_user_id - - metadata - filter: - _and: - - bucket_id: - _eq: default - - uploaded_by_user_id: - _eq: X-Hasura-User-Id -delete_permissions: - - role: user - permission: - filter: - uploaded_by_user_id: - _eq: X-Hasura-User-Id diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/storage_virus.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/storage_virus.yaml deleted file mode 100644 index 5c31429ce..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/storage_virus.yaml +++ /dev/null @@ -1,42 +0,0 @@ -table: - name: virus - schema: storage -configuration: - column_config: - created_at: - custom_name: createdAt - file_id: - custom_name: fileId - filename: - custom_name: filename - id: - custom_name: id - updated_at: - custom_name: updatedAt - user_session: - custom_name: userSession - virus: - custom_name: virus - custom_column_names: - created_at: createdAt - file_id: fileId - filename: filename - id: id - updated_at: updatedAt - user_session: userSession - virus: virus - custom_name: virus - custom_root_fields: - delete: deleteViruses - delete_by_pk: deleteVirus - insert: insertViruses - insert_one: insertVirus - select: viruses - select_aggregate: virusesAggregate - select_by_pk: virus - update: updateViruses - update_by_pk: updateVirus -object_relationships: - - name: file - using: - foreign_key_constraint_on: file_id diff --git a/examples/demos/backend/nhost/metadata/databases/default/tables/tables.yaml b/examples/demos/backend/nhost/metadata/databases/default/tables/tables.yaml deleted file mode 100644 index 8c8535fe8..000000000 --- a/examples/demos/backend/nhost/metadata/databases/default/tables/tables.yaml +++ /dev/null @@ -1,13 +0,0 @@ -- "!include auth_provider_requests.yaml" -- "!include auth_providers.yaml" -- "!include auth_refresh_token_types.yaml" -- "!include auth_refresh_tokens.yaml" -- "!include auth_roles.yaml" -- "!include auth_user_providers.yaml" -- "!include auth_user_roles.yaml" -- "!include auth_user_security_keys.yaml" -- "!include auth_users.yaml" -- "!include public_todos.yaml" -- "!include storage_buckets.yaml" -- "!include storage_files.yaml" -- "!include storage_virus.yaml" diff --git a/examples/demos/backend/nhost/metadata/graphql_schema_introspection.yaml b/examples/demos/backend/nhost/metadata/graphql_schema_introspection.yaml deleted file mode 100644 index 61a4dcac2..000000000 --- a/examples/demos/backend/nhost/metadata/graphql_schema_introspection.yaml +++ /dev/null @@ -1 +0,0 @@ -disabled_for_roles: [] diff --git a/examples/demos/backend/nhost/metadata/inherited_roles.yaml b/examples/demos/backend/nhost/metadata/inherited_roles.yaml deleted file mode 100644 index fe51488c7..000000000 --- a/examples/demos/backend/nhost/metadata/inherited_roles.yaml +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/demos/backend/nhost/metadata/metrics_config.yaml b/examples/demos/backend/nhost/metadata/metrics_config.yaml deleted file mode 100644 index 0967ef424..000000000 --- a/examples/demos/backend/nhost/metadata/metrics_config.yaml +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/examples/demos/backend/nhost/metadata/network.yaml b/examples/demos/backend/nhost/metadata/network.yaml deleted file mode 100644 index 0967ef424..000000000 --- a/examples/demos/backend/nhost/metadata/network.yaml +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/examples/demos/backend/nhost/metadata/opentelemetry.yaml b/examples/demos/backend/nhost/metadata/opentelemetry.yaml deleted file mode 100644 index 0967ef424..000000000 --- a/examples/demos/backend/nhost/metadata/opentelemetry.yaml +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/examples/demos/backend/nhost/metadata/query_collections.yaml b/examples/demos/backend/nhost/metadata/query_collections.yaml deleted file mode 100644 index fe51488c7..000000000 --- a/examples/demos/backend/nhost/metadata/query_collections.yaml +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/demos/backend/nhost/metadata/remote_schemas.yaml b/examples/demos/backend/nhost/metadata/remote_schemas.yaml deleted file mode 100644 index fe51488c7..000000000 --- a/examples/demos/backend/nhost/metadata/remote_schemas.yaml +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/demos/backend/nhost/metadata/rest_endpoints.yaml b/examples/demos/backend/nhost/metadata/rest_endpoints.yaml deleted file mode 100644 index fe51488c7..000000000 --- a/examples/demos/backend/nhost/metadata/rest_endpoints.yaml +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/demos/backend/nhost/metadata/version.yaml b/examples/demos/backend/nhost/metadata/version.yaml deleted file mode 100644 index 0a70affa4..000000000 --- a/examples/demos/backend/nhost/metadata/version.yaml +++ /dev/null @@ -1 +0,0 @@ -version: 3 diff --git a/examples/demos/backend/nhost/migrations/default/1757415711127_todos/down.sql b/examples/demos/backend/nhost/migrations/default/1757415711127_todos/down.sql deleted file mode 100644 index 11b190226..000000000 --- a/examples/demos/backend/nhost/migrations/default/1757415711127_todos/down.sql +++ /dev/null @@ -1 +0,0 @@ --- Could not auto-generate a down migration. diff --git a/examples/demos/backend/nhost/migrations/default/1757415711127_todos/up.sql b/examples/demos/backend/nhost/migrations/default/1757415711127_todos/up.sql deleted file mode 100644 index 9a24fefef..000000000 --- a/examples/demos/backend/nhost/migrations/default/1757415711127_todos/up.sql +++ /dev/null @@ -1,26 +0,0 @@ -CREATE TABLE public.todos ( - id uuid DEFAULT gen_random_uuid() NOT NULL, - created_at timestamptz DEFAULT now() NOT NULL, - updated_at timestamptz DEFAULT now() NOT NULL, - title text NOT NULL, - details text, - completed bool DEFAULT false NOT NULL, - user_id uuid NOT NULL, - PRIMARY KEY (id), - FOREIGN KEY (user_id) REFERENCES auth.users (id) ON UPDATE CASCADE ON DELETE CASCADE -); - - -CREATE OR REPLACE FUNCTION update_updated_at_column() -RETURNS TRIGGER AS $$ -BEGIN - NEW.updated_at = now(); - RETURN NEW; -END; -$$ language 'plpgsql'; - - -CREATE TRIGGER update_todos_updated_at - BEFORE UPDATE ON public.todos - FOR EACH ROW - EXECUTE FUNCTION update_updated_at_column(); diff --git a/examples/demos/backend/nhost/nhost.toml b/examples/demos/backend/nhost/nhost.toml deleted file mode 100644 index 0367d8019..000000000 --- a/examples/demos/backend/nhost/nhost.toml +++ /dev/null @@ -1,203 +0,0 @@ -[global] - -[hasura] -version = 'v2.48.5-ce' -adminSecret = '{{ secrets.HASURA_GRAPHQL_ADMIN_SECRET }}' -webhookSecret = '{{ secrets.NHOST_WEBHOOK_SECRET }}' - -[[hasura.jwtSecrets]] -type = 'HS256' -key = '{{ secrets.HASURA_GRAPHQL_JWT_SECRET }}' - -[hasura.settings] -corsDomain = ['*'] -devMode = true -enableAllowList = false -enableConsole = true -enableRemoteSchemaPermissions = false -enabledAPIs = ['metadata', 'graphql', 'pgdump', 'config'] -inferFunctionPermissions = true -liveQueriesMultiplexedRefetchInterval = 1000 -stringifyNumericTypes = false - -[hasura.logs] -level = 'warn' - -[hasura.events] -httpPoolSize = 100 - -[functions] -[functions.node] -version = 22 - -[auth] -version = '0.42.2' - -[auth.elevatedPrivileges] -mode = 'disabled' - -[auth.redirections] -clientUrl = 'http://localhost:3000' -allowedUrls = ['http://localhost:5173', 'exp://192.168.1.103:8081'] - -[auth.signUp] -enabled = true -disableNewUsers = false - -[auth.user] -[auth.user.roles] -default = 'user' -allowed = ['user', 'me'] - -[auth.user.locale] -default = 'en' -allowed = ['en'] - -[auth.user.gravatar] -enabled = true -default = 'blank' -rating = 'g' - -[auth.user.email] - -[auth.user.emailDomains] - -[auth.session] -[auth.session.accessToken] -expiresIn = 900 - -[auth.session.refreshToken] -expiresIn = 2592000 - -[auth.method] -[auth.method.anonymous] -enabled = false - -[auth.method.emailPasswordless] -enabled = true - -[auth.method.otp] -[auth.method.otp.email] -enabled = false - -[auth.method.emailPassword] -hibpEnabled = false -emailVerificationRequired = true -passwordMinLength = 9 - -[auth.method.smsPasswordless] -enabled = false - -[auth.method.oauth] -[auth.method.oauth.apple] -enabled = true -teamId = '{{ secrets.APPLE_TEAM_ID }}' -clientId = '{{ secrets.APPLE_CLIENT_ID }}' -audience = '{{ secrets.APPLE_AUDIENCE }}' -keyId = '{{ secrets.APPLE_KEY_ID }}' -privateKey = '{{ secrets.APPLE_PRIVATE_KEY }}' - -[auth.method.oauth.azuread] -tenant = 'common' -enabled = false - -[auth.method.oauth.bitbucket] -enabled = false - -[auth.method.oauth.discord] -enabled = false - -[auth.method.oauth.facebook] -enabled = false - -[auth.method.oauth.github] -enabled = true -clientId = '{{ secrets.GITHUB_CLIENT_ID }}' -clientSecret = '{{ secrets.GITHUB_CLIENT_SECRET }}' - -[auth.method.oauth.gitlab] -enabled = false - -[auth.method.oauth.google] -enabled = false - -[auth.method.oauth.linkedin] -enabled = false - -[auth.method.oauth.spotify] -enabled = false - -[auth.method.oauth.strava] -enabled = false - -[auth.method.oauth.twitch] -enabled = false - -[auth.method.oauth.twitter] -enabled = false - -[auth.method.oauth.windowslive] -enabled = false - -[auth.method.oauth.workos] -enabled = false - -[auth.method.webauthn] -enabled = true - -[auth.method.webauthn.relyingParty] -id = 'localhost' -name = 'nhost-sdk-experiment' -origins = ['http://localhost:3000', 'http://localhost:5173'] - -[auth.method.webauthn.attestation] -timeout = 60000 - -[auth.totp] -enabled = true -issuer = 'new-sdk' - -[auth.misc] -concealErrors = false - -[auth.rateLimit] -[auth.rateLimit.emails] -limit = 10 -interval = '1h' - -[auth.rateLimit.sms] -limit = 100 -interval = '1h' - -[auth.rateLimit.bruteForce] -limit = 100 -interval = '5m' - -[auth.rateLimit.signups] -limit = 100 -interval = '5m' - -[auth.rateLimit.global] -limit = 1000 -interval = '1m' - -[postgres] -version = '17.5-20250728-1' - -[postgres.resources] -[postgres.resources.storage] -capacity = 1 - -[provider] - -[storage] -version = '0.8.2' - -[observability] -[observability.grafana] -adminPassword = '{{ secrets.GRAFANA_ADMIN_PASSWORD }}' - -[observability.grafana.alerting] -enabled = false - -[observability.grafana.contacts] diff --git a/examples/demos/express/README.md b/examples/demos/express/README.md deleted file mode 100644 index 42777732c..000000000 --- a/examples/demos/express/README.md +++ /dev/null @@ -1,184 +0,0 @@ -# Express with Nhost SDK Demo - -This demo showcases how to integrate the Nhost SDK with an Express server, demonstrating two authentication methods for server-side applications. - -## Overview - -This demo shows how to: - -1. Create an SSR (Server-Side Rendering) Nhost client in an Express application -2. Handle authentication using cookies -3. Handle authentication using Authorization headers (JWT tokens) -4. Make authenticated GraphQL requests to retrieve data - -## Setup - -1. Clone the repository and navigate to this demo directory: - -```bash -cd sdk-experiment/demos/express -``` - -2. Install dependencies: - -```bash -pnpm install -``` - -3. Start the local Nhost backend (from the root directory): - -```bash -cd ../.. -pnpm nhost:dev -``` - -4. Start the Express server: - -```bash -cd demos/express -pnpm dev -``` - -The server will start on port 4000. - -## Authentication Methods - -### 1. Cookie-based Authentication - -This method reads the Nhost session from cookies passed in the HTTP request. It provides full session information including user details. - -```typescript -const nhostClientFromCookies = (req: Request) => { - return createSSRClient({ - subdomain: "local", - region: "local", - storage: { - get: (): Session | null => { - const s = req.cookies.nhostSession || null; - if (!s) { - return null; - } - const session = JSON.parse(s) as Session; - return session; - }, - // ... other handlers - }, - }); -}; -``` - -### 2. Authorization Header Authentication - -This method reads the JWT token from the Authorization header. Note that this provides only partial session information (just the access token). - -```typescript -const nhostClientFromAuthHeader = (req: Request) => { - return createSSRClient({ - subdomain: "local", - region: "local", - storage: { - get: (): Session | null => { - const s = req.headers.authorization || null; - if (!s) { - return null; - } - // Extract token from "Bearer " - const token = s.split(" ")[1]; - const session = { accessToken: token } as Session; - return session; - }, - // ... other handlers - }, - }); -}; -``` - -## API Endpoints - -The server has two endpoints that demonstrate both authentication methods: - -- `POST /cookies` - Authenticates using cookies -- `POST /auth-header` - Authenticates using the Authorization header - -Both endpoints retrieve a list of files using GraphQL after authenticating the user. - -## Testing - -Use the included curl script to test both authentication methods: - -```bash -# Run the curl commands -./curl.sh -``` - -### Example Requests - -#### Using cookies: - -```bash -curl \ - -X POST \ - -b "nhostSession=%7B%22accessToken%22%3A%22eyJhbGci...%22%7D" \ - http://localhost:4000/cookies -``` - -#### Using authorization header: - -```bash -curl \ - -X POST \ - -H "Authorization: Bearer eyJhbGci..." \ - http://localhost:4000/auth-header -``` - -## Response Example - -Both endpoints return similar responses: - -```json -{ - "session": { - "accessToken": "eyJhbGci...", - "accessTokenExpiresIn": 900, - "refreshToken": "3038a6aa-caf2-48c8-b901-bd626bb7494c", - "refreshTokenId": "74376dd5-ff33-4b2c-bced-a0b847facfe9", - "user": { - "avatarUrl": "https://www.gravatar.com/avatar/a52a0027726bf3a4ec2728489732b38d?d=blank&r=g", - "createdAt": "2025-05-20T12:15:35.232886Z", - "defaultRole": "user", - "displayName": "asd", - "email": "asdsad@asd.com", - "emailVerified": true, - "id": "5cc1b449-9912-4080-95f7-3d270305bc62", - "isAnonymous": false, - "locale": "en", - "metadata": null, - "phoneNumberVerified": false, - "roles": ["user", "me"] - } - }, - "files": [ - { - "id": "1a4cbc24-0f43-4734-84dc-fbec0e615cb4", - "name": "Screenshot 2025-05-19 at 15.08.43.png", - "size": 42815, - "mimeType": "image/png", - "bucketId": "default", - "uploadedByUserId": "5cc1b449-9912-4080-95f7-3d270305bc62" - } - ] -} -``` - -## Key Concepts - -- **SSR Client**: The `createSSRClient` function creates a special version of the Nhost client optimized for server-side environments. -- **Custom Storage**: We implement custom storage handlers to retrieve session data from HTTP requests rather than browser storage. -- **Authentication Flexibility**: The demo shows how to support both cookie-based and header-based authentication schemes. - -## Next Steps - -- Add error handling middleware -- Implement refresh token rotation -- Add more examples of GraphQL operations -- Integrate with a frontend application diff --git a/examples/demos/express/curl.sh b/examples/demos/express/curl.sh deleted file mode 100644 index 93135928f..000000000 --- a/examples/demos/express/curl.sh +++ /dev/null @@ -1,13 +0,0 @@ -#/usr/bin/env bash - -# using cookies (URL encoded session), test by extracting from browser dev tools -curl \ - -X POST \ - -b "nhostSession=%7B%22accessToken%22%3A%22eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTY3MzcwMzUsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJ1c2VyIiwibWUiXSwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLXVzZXItaWQiOiI1ZDA0Y2ZmMS0yMDZjLTQ4ZTgtODYzYy1iZWM3YzMyNGVjZTciLCJ4LWhhc3VyYS11c2VyLWlzLWFub255bW91cyI6ImZhbHNlIn0sImlhdCI6MTc1NjczNjk3MCwiaXNzIjoiaGFzdXJhLWF1dGgiLCJzdWIiOiI1ZDA0Y2ZmMS0yMDZjLTQ4ZTgtODYzYy1iZWM3YzMyNGVjZTcifQ.53LbshT0SRc9ur3zHh9vI4-1w18iE77RYrsK0eP2RYc%22%2C%22accessTokenExpiresIn%22%3A65%2C%22refreshToken%22%3A%22631a6313-cd97-4e41-8dc9-32ceeab67df1%22%2C%22refreshTokenId%22%3A%2265e7003a-1031-41ed-9df9-647f5c303455%22%2C%22user%22%3A%7B%22activeMfaType%22%3Anull%2C%22avatarUrl%22%3A%22https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F6246622%3Fv%3D4%22%2C%22createdAt%22%3A%222025-09-01T13%3A50%3A30.312877Z%22%2C%22defaultRole%22%3A%22user%22%2C%22displayName%22%3A%22David%20Barroso%22%2C%22email%22%3A%22dbarrosop%40dravetech.com%22%2C%22emailVerified%22%3Atrue%2C%22id%22%3A%225d04cff1-206c-48e8-863c-bec7c324ece7%22%2C%22isAnonymous%22%3Afalse%2C%22locale%22%3A%22en%22%2C%22metadata%22%3Anull%2C%22phoneNumberVerified%22%3Afalse%2C%22roles%22%3A%5B%22user%22%2C%22me%22%5D%7D%2C%22decodedToken%22%3A%7B%22exp%22%3A1756737035000%2C%22https%3A%2F%2Fhasura.io%2Fjwt%2Fclaims%22%3A%7B%22x-hasura-allowed-roles%22%3A%5B%22user%22%2C%22me%22%5D%2C%22x-hasura-default-role%22%3A%22user%22%2C%22x-hasura-user-id%22%3A%225d04cff1-206c-48e8-863c-bec7c324ece7%22%2C%22x-hasura-user-is-anonymous%22%3A%22false%22%7D%2C%22iat%22%3A1756736970000%2C%22iss%22%3A%22hasura-auth%22%2C%22sub%22%3A%225d04cff1-206c-48e8-863c-bec7c324ece7%22%7D%7D" \ - http://localhost:4000/cookies - -# using Authorization header with the access token, test by extracting from browser dev tools -curl \ - -X POST \ - -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTY3MzY3NDUsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJ1c2VyIiwibWUiXSwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLXVzZXItaWQiOiI1ZDA0Y2ZmMS0yMDZjLTQ4ZTgtODYzYy1iZWM3YzMyNGVjZTciLCJ4LWhhc3VyYS11c2VyLWlzLWFub255bW91cyI6ImZhbHNlIn0sImlhdCI6MTc1NjczNjY4MCwiaXNzIjoiaGFzdXJhLWF1dGgiLCJzdWIiOiI1ZDA0Y2ZmMS0yMDZjLTQ4ZTgtODYzYy1iZWM3YzMyNGVjZTcifQ.0vhBD7vZ0OYxFlpiTelt0mZw5NSYvO26EcWbD3Wk3_M" \ - http://localhost:4000/auth-header diff --git a/examples/demos/express/package.json b/examples/demos/express/package.json deleted file mode 100644 index 6a6ab06a3..000000000 --- a/examples/demos/express/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "express", - "version": "1.0.0", - "license": "MIT", - "scripts": { - "dev": "pnpm ts-node src/index.ts", - "build": "tsc", - "generate": "echo 'Nothing to do'", - "test": "pnpm test:typecheck && pnpm test:lint", - "test:typecheck": "tsc --noEmit", - "test:lint": "biome check", - "format": "biome format --write" - }, - "dependencies": { - "@nhost/nhost-js": "workspace:^", - "cookie-parser": "^1.4.7", - "express": "^5.1.0" - }, - "devDependencies": { - "@types/cookie-parser": "^1.4.8", - "@types/express": "^5.0.2", - "ts-node": "^10.9.2" - } -} diff --git a/examples/demos/express/pnpm-lock.yaml b/examples/demos/express/pnpm-lock.yaml deleted file mode 100644 index c4b5df709..000000000 --- a/examples/demos/express/pnpm-lock.yaml +++ /dev/null @@ -1,838 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@nhost/nhost-js': - specifier: workspace:^ - version: link:../../../packages/nhost-js - cookie-parser: - specifier: ^1.4.7 - version: 1.4.7 - express: - specifier: ^5.1.0 - version: 5.1.0 - devDependencies: - '@types/cookie-parser': - specifier: ^1.4.8 - version: 1.4.9(@types/express@5.0.3) - '@types/express': - specifier: ^5.0.2 - version: 5.0.3 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@24.3.0)(typescript@5.9.2) - -packages: - - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - - '@tsconfig/node10@1.0.11': - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - - '@types/body-parser@1.19.6': - resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/cookie-parser@1.4.9': - resolution: {integrity: sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==} - peerDependencies: - '@types/express': '*' - - '@types/express-serve-static-core@5.0.7': - resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} - - '@types/express@5.0.3': - resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==} - - '@types/http-errors@2.0.5': - resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} - - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - - '@types/node@24.3.0': - resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} - - '@types/qs@6.14.0': - resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - - '@types/send@0.17.5': - resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} - - '@types/serve-static@1.15.8': - resolution: {integrity: sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==} - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - - body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} - engines: {node: '>=18'} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - content-disposition@1.0.0: - resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - cookie-parser@1.4.7: - resolution: {integrity: sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==} - engines: {node: '>= 0.8.0'} - - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - express@5.1.0: - resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} - engines: {node: '>= 18'} - - finalhandler@2.1.0: - resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} - engines: {node: '>= 0.8'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - iconv-lite@0.7.0: - resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} - engines: {node: '>=0.10.0'} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.1: - resolution: {integrity: sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==} - engines: {node: '>= 0.10'} - - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} - engines: {node: '>= 18'} - - serve-static@2.2.0: - resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} - engines: {node: '>= 18'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@7.10.0: - resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - -snapshots: - - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@tsconfig/node10@1.0.11': {} - - '@tsconfig/node12@1.0.11': {} - - '@tsconfig/node14@1.0.3': {} - - '@tsconfig/node16@1.0.4': {} - - '@types/body-parser@1.19.6': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 24.3.0 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 24.3.0 - - '@types/cookie-parser@1.4.9(@types/express@5.0.3)': - dependencies: - '@types/express': 5.0.3 - - '@types/express-serve-static-core@5.0.7': - dependencies: - '@types/node': 24.3.0 - '@types/qs': 6.14.0 - '@types/range-parser': 1.2.7 - '@types/send': 0.17.5 - - '@types/express@5.0.3': - dependencies: - '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 5.0.7 - '@types/serve-static': 1.15.8 - - '@types/http-errors@2.0.5': {} - - '@types/mime@1.3.5': {} - - '@types/node@24.3.0': - dependencies: - undici-types: 7.10.0 - - '@types/qs@6.14.0': {} - - '@types/range-parser@1.2.7': {} - - '@types/send@0.17.5': - dependencies: - '@types/mime': 1.3.5 - '@types/node': 24.3.0 - - '@types/serve-static@1.15.8': - dependencies: - '@types/http-errors': 2.0.5 - '@types/node': 24.3.0 - '@types/send': 0.17.5 - - accepts@2.0.0: - dependencies: - mime-types: 3.0.1 - negotiator: 1.0.0 - - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} - - arg@4.1.3: {} - - body-parser@2.2.0: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.1 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - on-finished: 2.4.1 - qs: 6.14.0 - raw-body: 3.0.1 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - - bytes@3.1.2: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - content-disposition@1.0.0: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - - cookie-parser@1.4.7: - dependencies: - cookie: 0.7.2 - cookie-signature: 1.0.6 - - cookie-signature@1.0.6: {} - - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - - create-require@1.1.1: {} - - debug@4.4.1: - dependencies: - ms: 2.1.3 - - depd@2.0.0: {} - - diff@4.0.2: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - ee-first@1.1.1: {} - - encodeurl@2.0.0: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - escape-html@1.0.3: {} - - etag@1.8.1: {} - - express@5.1.0: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.0 - content-disposition: 1.0.0 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.1 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.0 - fresh: 2.0.0 - http-errors: 2.0.0 - merge-descriptors: 2.0.0 - mime-types: 3.0.1 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.14.0 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.0 - serve-static: 2.2.0 - statuses: 2.0.2 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - finalhandler@2.1.0: - dependencies: - debug: 4.4.1 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - forwarded@0.2.0: {} - - fresh@2.0.0: {} - - function-bind@1.1.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - gopd@1.2.0: {} - - has-symbols@1.1.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - iconv-lite@0.7.0: - dependencies: - safer-buffer: 2.1.2 - - inherits@2.0.4: {} - - ipaddr.js@1.9.1: {} - - is-promise@4.0.0: {} - - make-error@1.3.6: {} - - math-intrinsics@1.1.0: {} - - media-typer@1.1.0: {} - - merge-descriptors@2.0.0: {} - - mime-db@1.54.0: {} - - mime-types@3.0.1: - dependencies: - mime-db: 1.54.0 - - ms@2.1.3: {} - - negotiator@1.0.0: {} - - object-inspect@1.13.4: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - parseurl@1.3.3: {} - - path-to-regexp@8.3.0: {} - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - qs@6.14.0: - dependencies: - side-channel: 1.1.0 - - range-parser@1.2.1: {} - - raw-body@3.0.1: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.7.0 - unpipe: 1.0.0 - - router@2.2.0: - dependencies: - debug: 4.4.1 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.3.0 - transitivePeerDependencies: - - supports-color - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - send@1.2.0: - dependencies: - debug: 4.4.1 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.0 - mime-types: 3.0.1 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - serve-static@2.2.0: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.0 - transitivePeerDependencies: - - supports-color - - setprototypeof@1.2.0: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - statuses@2.0.1: {} - - statuses@2.0.2: {} - - toidentifier@1.0.1: {} - - ts-node@10.9.2(@types/node@24.3.0)(typescript@5.9.2): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 24.3.0 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.9.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.1 - - typescript@5.9.2: {} - - undici-types@7.10.0: {} - - unpipe@1.0.0: {} - - v8-compile-cache-lib@3.0.1: {} - - vary@1.1.2: {} - - wrappy@1.0.2: {} - - yn@3.1.1: {} diff --git a/examples/demos/express/src/index.ts b/examples/demos/express/src/index.ts deleted file mode 100644 index b65f6c806..000000000 --- a/examples/demos/express/src/index.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { createServerClient } from "@nhost/nhost-js"; -import type { Session } from "@nhost/nhost-js/session"; -import type { FileMetadata } from "@nhost/nhost-js/storage"; -import cookieParser from "cookie-parser"; -import express, { type Request, type Response } from "express"; - -const app = express(); -const port = 4000; - -app.use(cookieParser()); -app.use(express.json()); - -// This is a simple example of how to use the Nhost client in an Express server -// reading the session from cookies passed in the request -const nhostClientFromCookies = (req: Request) => { - return createServerClient({ - subdomain: "local", - region: "local", - storage: { - get: (): Session | null => { - return (JSON.parse(req.cookies.nhostSession) || null) as Session | null; - }, - set: () => { - throw new Error("It is easier to handle the session in the client"); - }, - remove: () => { - throw new Error("It is easier to handle the session in the client"); - }, - }, - }); -}; - -// This is a simple example of how to use the Nhost client in an Express server -// reading the Authorization header passed in the request. Note in this case -// the session only has partial information. -const nhostClientFromAuthHeader = (req: Request) => { - return createServerClient({ - subdomain: "local", - region: "local", - storage: { - get: (): Session | null => { - const s = req.headers.authorization || null; - if (!s) { - return null; - } - - if (typeof s !== "string") { - return null; - } - - const token = s.split(" ")[1]; - if (!token) { - return null; - } - const session = { accessToken: token } as Session; - return session; - }, - set: () => { - throw new Error("It is easier to handle the session in the client"); - }, - remove: () => { - throw new Error("It is easier to handle the session in the client"); - }, - }, - }); -}; - -interface GraphqlGetFilesResponse { - files: FileMetadata[]; -} - -app.post("/cookies", async (req: Request, res: Response) => { - const nhost = nhostClientFromCookies(req); - - try { - const response = await nhost.graphql.request({ - query: `query GetFiles { - files { - id - name - size - mimeType - bucketId - uploadedByUserId - } - }`, - }); - res.json({ - session: nhost.getUserSession(), - files: response.body.data?.files, - }); - } catch (error) { - const err = error as Error; - res.status(500).json({ error: err?.message }); - return; - } -}); - -app.post("/auth-header", async (req: Request, res: Response) => { - const nhost = nhostClientFromAuthHeader(req); - try { - const response = await nhost.graphql.request({ - query: `query GetFiles { - files { - id - name - size - mimeType - bucketId - uploadedByUserId - } - }`, - }); - res.json({ - session: nhost.getUserSession(), - files: response.body.data?.files, - }); - } catch (error) { - const err = error as Error; - res.status(500).json({ error: err?.message }); - } -}); - -app.listen(port, () => { - console.log(`Example app listening on port ${port}`); -}); diff --git a/examples/demos/express/tsconfig.json b/examples/demos/express/tsconfig.json deleted file mode 100644 index 9c849eba1..000000000 --- a/examples/demos/express/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "sourceMap": true, - "outDir": "dist", - "strict": true, - "lib": ["esnext"], - "skipLibCheck": true, - "esModuleInterop": true - } -} diff --git a/examples/demos/nextjs-ssr-demo/.gitignore b/examples/demos/nextjs-ssr-demo/.gitignore deleted file mode 100644 index 5ef6a5207..000000000 --- a/examples/demos/nextjs-ssr-demo/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files (can opt-in for committing if needed) -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/examples/demos/nextjs-ssr-demo/README.md b/examples/demos/nextjs-ssr-demo/README.md deleted file mode 100644 index 9226b4633..000000000 --- a/examples/demos/nextjs-ssr-demo/README.md +++ /dev/null @@ -1,164 +0,0 @@ -# Next.js SSR Demo with Nhost - -This project demonstrates how to integrate Nhost with Next.js, showcasing server-side rendering (SSR) capabilities and authentication flows. It includes features like file uploads, session management, middleware for route protection, and client-side interactions for interactive components. - -## Getting Started - -To run the demo locally: - -1. Clone this repository -2. Start the Nhost backend: - -```bash -cd backend -nhost up -``` - -3. Start the Next.js application: - -```bash -cd demos/nextjs-ssr-demo -pnpm install -pnpm dev -``` - -The application will be available at [http://localhost:3000](http://localhost:3000). - -### Environment Configuration - -The application uses the following environment variables: - -- `NHOST_REGION` - The region where your Nhost project is located (defaults to "local") -- `NHOST_SUBDOMAIN` - The subdomain of your Nhost project (defaults to "local") - -## Nhost SDK Integration - -This project demonstrates how to effectively use the Nhost SDK with Next.js in a server-side rendering (SSR) setup. Most of the application is built using server components, which allows for better performance and SEO. Most of the code is either generic Next.js code or vanilla Nhost code. - -### Server and Client Components - -The special integration code needed to handle server + client components and the Next.js middleware can be found under: - -- `src/app/lib/nhost/client/index.tsx` - This file exports: - - `createNhostClient` initializes an Nhost client using CookieStorage to be used in client components. -- `src/app/lib/nhost/server/index.tsx` - This file exports: - - `createNhostClient` initializes an Nhost client using CookieStorage to be used in server components. - - `handleNhostMiddleware` handles the initialization of an Nhost client that can be used in Next.js middleware and refreshes the session if needed. -- `src/app/lib/nhost/AuthProvider.tsx` - This file provides: - - Client-side authentication context with session state management - - Cross-tab session synchronization using `sessionStorage.onChange` - - Refresh token change detection for middleware-driven session updates - - Page visibility and focus event handling for session state consistency - -The key differences in the implementation: - -- **Client Components** - - - Uses `CookieStorage` for persistent session management - - Enables client-side operations like file uploads and MFA configuration - - Provides authentication context with cross-tab session synchronization - - Handles session state changes from middleware and other tabs - -- **Server Components** - - Custom storage implementation utilizing cookies compatible with Next.js server components - - Disables auto-refresh token feature as server components can't write cookies - - Supports server-side data fetching and rendering - -### Cookie-Based Session Persistence - -A key aspect of this integration is how the session is persisted across server and client components: - -- Both server and client components use cookie-based storage -- The server implementation reads cookies using Next.js's `cookies()` API -- The middleware implementation has its own cookie handling to read from request cookies and write to response cookies -- The session is stored using the default session key from the SDK (`nhostSession`) -- The refresh token mechanism is handled by the middleware to ensure session continuity -- Client-side AuthProvider synchronizes session state across tabs and detects middleware-driven session changes -- Cross-tab session expiration is handled by monitoring `sessionStorage.onChange` events - -### Middleware for Route Protection - -The middleware (`src/middleware.ts`) is used to protect routes and handle refreshing the tokens. It handles: - -- Route protection for authenticated pages -- Session token refreshing -- Redirecting unauthenticated users to the sign-in page - -Public routes (like `/signin`, `/signup`, and `/verify`) are explicitly allowed without authentication. - -### Authentication Features - -All authentication steps are performed server-side and rely on the vanilla nhost-js SDK. No special code or considerations are needed for this. The demo supports multiple authentication methods, including: - -- Email and Password with optional MFA -- Magic Link authentication - -You can find all the relevant code in the folders: - -- `src/app/signin/` - Sign in methods -- `src/app/signup/` - Sign up methods -- `src/app/verify/` - Route to verify the magic link. We use a route because server components are not allowed to write cookies. Alternatively, this could be done on a client component as those are allowed to write cookies, but we wanted to keep the sign-in flow as server components for demonstration purposes. - -### Profile Management - -The profile page is a server component that fetches the session data from the persisted session cookie. In addition, the profile page allows users to configure their MFA. - -There are three peculiarities with the profile page: - -1. The session is read on the server from the cookie so the profile can be rendered server-side. -2. The MFA configuration is done using a client component to provide interactivity. -3. Similarly, changing the password is done client-side. - -You can find all the relevant code in the folder: - -- `src/app/profile/` - -### GraphQL Integration - -The application demonstrates how to use Nhost's GraphQL client in both server and client components. - -### File Storage Implementation - -The application demonstrates how to use Nhost's file storage capabilities. While the `/upload` page is fully pre-rendered server-side, all interactions in this page are handled by client components. This allows the user to upload/download files directly to the storage service. - -Some details about the page: - -1. The page is fully rendered server-side, including the list of files, which are retrieved using GraphQL. -2. All the storage interactions (uploading, downloading, deleting) are handled by client components. -3. The download is done by using authenticated requests. This requires a bit of post-processing as we need to fetch the file with the SDK and then create a blob URL to download the file but it is much more efficient than presigned URLs as we can leverage the CDN for caching. -4. To avoid re-fetching the list of files on every interaction, we push/remove the file to/from the list of files in the client component. This is done using a custom hook that uses the `useState` and `useEffect` hooks to manage the state of the files. - -You can find the code for the `/upload` page in the folder: - -- `src/app/upload/` - -### Layout and Navigation - -The layout is a server component that will render different content depending on the authentication state of the user: - -- If the user is authenticated, the layout will render the navigation bar with the profile and upload links. -- If the user is not authenticated, the layout will render the sign in and sign up links. - -To make sure the navigation is always up to date, every server component that changes the authentication state will call `revalidateAfterAuthChange` to revalidate the layout. This is done using the `revalidatePath` function from Next.js. - -## Development Tooling - -This demo uses: - -- Next.js 15 with App Router -- Turbopack for faster development experience (via `--turbopack` flag) -- TypeScript for type safety -- React 19 - -## Key Nhost SDK Features Used - -- **Authentication** - Sign in/up, Magic Links, MFA -- **GraphQL** - Data fetching for files and user information -- **Storage** - File uploads and downloads -- **Cookies** - Session persistence across server and client components -- **Middleware Integration** - Seamless route protection - -## Learn More - -- [Nhost Documentation](https://docs.nhost.io) -- [Next.js Documentation](https://nextjs.org/docs) diff --git a/examples/demos/nextjs-ssr-demo/next.config.ts b/examples/demos/nextjs-ssr-demo/next.config.ts deleted file mode 100644 index e9ffa3083..000000000 --- a/examples/demos/nextjs-ssr-demo/next.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ -}; - -export default nextConfig; diff --git a/examples/demos/nextjs-ssr-demo/package.json b/examples/demos/nextjs-ssr-demo/package.json deleted file mode 100644 index 0871f8e36..000000000 --- a/examples/demos/nextjs-ssr-demo/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "nextjs-demo", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev --turbopack", - "build": "next build", - "start": "next start", - "generate": "echo 'Nothing to do'", - "test": "pnpm test:typecheck && pnpm test:lint", - "test:typecheck": "tsc --noEmit", - "test:lint": "biome check", - "format": "biome format --write" - }, - "dependencies": { - "@nhost/nhost-js": "workspace:*", - "@simplewebauthn/browser": "^13.1.0", - "next": "15.4.7", - "react": "^18.2.0", - "react-dom": "^18.2.0" - }, - "devDependencies": { - "@types/node": "^20.17.23", - "@types/react": "^18", - "@types/react-dom": "^18", - "globals": "^16.0.0" - } -} diff --git a/examples/demos/nextjs-ssr-demo/pnpm-lock.yaml b/examples/demos/nextjs-ssr-demo/pnpm-lock.yaml deleted file mode 100644 index 293d657dd..000000000 --- a/examples/demos/nextjs-ssr-demo/pnpm-lock.yaml +++ /dev/null @@ -1,633 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@nhost/nhost-js': - specifier: workspace:* - version: link:../../../packages/nhost-js - '@simplewebauthn/browser': - specifier: ^13.1.0 - version: 13.1.2 - next: - specifier: 15.4.7 - version: 15.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: - specifier: ^18.2.0 - version: 18.3.1 - react-dom: - specifier: ^18.2.0 - version: 18.3.1(react@18.3.1) - devDependencies: - '@types/node': - specifier: ^20.17.23 - version: 20.19.13 - '@types/react': - specifier: ^18 - version: 18.3.24 - '@types/react-dom': - specifier: ^18 - version: 18.3.7(@types/react@18.3.24) - globals: - specifier: ^16.0.0 - version: 16.3.0 - -packages: - - '@emnapi/runtime@1.5.0': - resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} - - '@img/sharp-darwin-arm64@0.34.3': - resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [darwin] - - '@img/sharp-darwin-x64@0.34.3': - resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-darwin-arm64@1.2.0': - resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} - cpu: [arm64] - os: [darwin] - - '@img/sharp-libvips-darwin-x64@1.2.0': - resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-linux-arm64@1.2.0': - resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} - cpu: [arm64] - os: [linux] - - '@img/sharp-libvips-linux-arm@1.2.0': - resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} - cpu: [arm] - os: [linux] - - '@img/sharp-libvips-linux-ppc64@1.2.0': - resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} - cpu: [ppc64] - os: [linux] - - '@img/sharp-libvips-linux-s390x@1.2.0': - resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} - cpu: [s390x] - os: [linux] - - '@img/sharp-libvips-linux-x64@1.2.0': - resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} - cpu: [x64] - os: [linux] - - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} - cpu: [arm64] - os: [linux] - - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} - cpu: [x64] - os: [linux] - - '@img/sharp-linux-arm64@0.34.3': - resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - - '@img/sharp-linux-arm@0.34.3': - resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - - '@img/sharp-linux-ppc64@0.34.3': - resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ppc64] - os: [linux] - - '@img/sharp-linux-s390x@0.34.3': - resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [s390x] - os: [linux] - - '@img/sharp-linux-x64@0.34.3': - resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - - '@img/sharp-linuxmusl-arm64@0.34.3': - resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - - '@img/sharp-linuxmusl-x64@0.34.3': - resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - - '@img/sharp-wasm32@0.34.3': - resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [wasm32] - - '@img/sharp-win32-arm64@0.34.3': - resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [win32] - - '@img/sharp-win32-ia32@0.34.3': - resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ia32] - os: [win32] - - '@img/sharp-win32-x64@0.34.3': - resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [win32] - - '@next/env@15.4.7': - resolution: {integrity: sha512-PrBIpO8oljZGTOe9HH0miix1w5MUiGJ/q83Jge03mHEE0E3pyqzAy2+l5G6aJDbXoobmxPJTVhbCuwlLtjSHwg==} - - '@next/swc-darwin-arm64@15.4.7': - resolution: {integrity: sha512-2Dkb+VUTp9kHHkSqtws4fDl2Oxms29HcZBwFIda1X7Ztudzy7M6XF9HDS2dq85TmdN47VpuhjE+i6wgnIboVzQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@15.4.7': - resolution: {integrity: sha512-qaMnEozKdWezlmh1OGDVFueFv2z9lWTcLvt7e39QA3YOvZHNpN2rLs/IQLwZaUiw2jSvxW07LxMCWtOqsWFNQg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@15.4.7': - resolution: {integrity: sha512-ny7lODPE7a15Qms8LZiN9wjNWIeI+iAZOFDOnv2pcHStncUr7cr9lD5XF81mdhrBXLUP9yT9RzlmSWKIazWoDw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@15.4.7': - resolution: {integrity: sha512-4SaCjlFR/2hGJqZLLWycccy1t+wBrE/vyJWnYaZJhUVHccpGLG5q0C+Xkw4iRzUIkE+/dr90MJRUym3s1+vO8A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-x64-gnu@15.4.7': - resolution: {integrity: sha512-2uNXjxvONyRidg00VwvlTYDwC9EgCGNzPAPYbttIATZRxmOZ3hllk/YYESzHZb65eyZfBR5g9xgCZjRAl9YYGg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@15.4.7': - resolution: {integrity: sha512-ceNbPjsFgLscYNGKSu4I6LYaadq2B8tcK116nVuInpHHdAWLWSwVK6CHNvCi0wVS9+TTArIFKJGsEyVD1H+4Kg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-win32-arm64-msvc@15.4.7': - resolution: {integrity: sha512-pZyxmY1iHlZJ04LUL7Css8bNvsYAMYOY9JRwFA3HZgpaNKsJSowD09Vg2R9734GxAcLJc2KDQHSCR91uD6/AAw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-x64-msvc@15.4.7': - resolution: {integrity: sha512-HjuwPJ7BeRzgl3KrjKqD2iDng0eQIpIReyhpF5r4yeAHFwWRuAhfW92rWv/r3qeQHEwHsLRzFDvMqRjyM5DI6A==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@simplewebauthn/browser@13.1.2': - resolution: {integrity: sha512-aZnW0KawAM83fSBUgglP5WofbrLbLyr7CoPqYr66Eppm7zO86YX6rrCjRB3hQKPrL7ATvY4FVXlykZ6w6FwYYw==} - - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - - '@types/node@20.19.13': - resolution: {integrity: sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==} - - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} - peerDependencies: - '@types/react': ^18.0.0 - - '@types/react@18.3.24': - resolution: {integrity: sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==} - - caniuse-lite@1.0.30001739: - resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==} - - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} - engines: {node: '>=8'} - - globals@16.3.0: - resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==} - engines: {node: '>=18'} - - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - next@15.4.7: - resolution: {integrity: sha512-OcqRugwF7n7mC8OSYjvsZhhG1AYSvulor1EIUsIkbbEbf1qoE5EbH36Swj8WhF4cHqmDgkiam3z1c1W0J1Wifg==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.51.1 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 - - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} - - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - - sharp@0.34.3: - resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - -snapshots: - - '@emnapi/runtime@1.5.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@img/sharp-darwin-arm64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.0 - optional: true - - '@img/sharp-darwin-x64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.0 - optional: true - - '@img/sharp-libvips-darwin-arm64@1.2.0': - optional: true - - '@img/sharp-libvips-darwin-x64@1.2.0': - optional: true - - '@img/sharp-libvips-linux-arm64@1.2.0': - optional: true - - '@img/sharp-libvips-linux-arm@1.2.0': - optional: true - - '@img/sharp-libvips-linux-ppc64@1.2.0': - optional: true - - '@img/sharp-libvips-linux-s390x@1.2.0': - optional: true - - '@img/sharp-libvips-linux-x64@1.2.0': - optional: true - - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - optional: true - - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - optional: true - - '@img/sharp-linux-arm64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.0 - optional: true - - '@img/sharp-linux-arm@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.0 - optional: true - - '@img/sharp-linux-ppc64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.0 - optional: true - - '@img/sharp-linux-s390x@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.0 - optional: true - - '@img/sharp-linux-x64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.0 - optional: true - - '@img/sharp-linuxmusl-arm64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - optional: true - - '@img/sharp-linuxmusl-x64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - optional: true - - '@img/sharp-wasm32@0.34.3': - dependencies: - '@emnapi/runtime': 1.5.0 - optional: true - - '@img/sharp-win32-arm64@0.34.3': - optional: true - - '@img/sharp-win32-ia32@0.34.3': - optional: true - - '@img/sharp-win32-x64@0.34.3': - optional: true - - '@next/env@15.4.7': {} - - '@next/swc-darwin-arm64@15.4.7': - optional: true - - '@next/swc-darwin-x64@15.4.7': - optional: true - - '@next/swc-linux-arm64-gnu@15.4.7': - optional: true - - '@next/swc-linux-arm64-musl@15.4.7': - optional: true - - '@next/swc-linux-x64-gnu@15.4.7': - optional: true - - '@next/swc-linux-x64-musl@15.4.7': - optional: true - - '@next/swc-win32-arm64-msvc@15.4.7': - optional: true - - '@next/swc-win32-x64-msvc@15.4.7': - optional: true - - '@simplewebauthn/browser@13.1.2': {} - - '@swc/helpers@0.5.15': - dependencies: - tslib: 2.8.1 - - '@types/node@20.19.13': - dependencies: - undici-types: 6.21.0 - - '@types/prop-types@15.7.15': {} - - '@types/react-dom@18.3.7(@types/react@18.3.24)': - dependencies: - '@types/react': 18.3.24 - - '@types/react@18.3.24': - dependencies: - '@types/prop-types': 15.7.15 - csstype: 3.1.3 - - caniuse-lite@1.0.30001739: {} - - client-only@0.0.1: {} - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - optional: true - - color-name@1.1.4: - optional: true - - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - - csstype@3.1.3: {} - - detect-libc@2.0.4: - optional: true - - globals@16.3.0: {} - - is-arrayish@0.3.2: - optional: true - - js-tokens@4.0.0: {} - - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - - nanoid@3.3.11: {} - - next@15.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@next/env': 15.4.7 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001739 - postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.6(react@18.3.1) - optionalDependencies: - '@next/swc-darwin-arm64': 15.4.7 - '@next/swc-darwin-x64': 15.4.7 - '@next/swc-linux-arm64-gnu': 15.4.7 - '@next/swc-linux-arm64-musl': 15.4.7 - '@next/swc-linux-x64-gnu': 15.4.7 - '@next/swc-linux-x64-musl': 15.4.7 - '@next/swc-win32-arm64-msvc': 15.4.7 - '@next/swc-win32-x64-msvc': 15.4.7 - sharp: 0.34.3 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - picocolors@1.1.1: {} - - postcss@8.4.31: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - react-dom@18.3.1(react@18.3.1): - dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 - - react@18.3.1: - dependencies: - loose-envify: 1.4.0 - - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 - - semver@7.7.2: - optional: true - - sharp@0.34.3: - dependencies: - color: 4.2.3 - detect-libc: 2.0.4 - semver: 7.7.2 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.3 - '@img/sharp-darwin-x64': 0.34.3 - '@img/sharp-libvips-darwin-arm64': 1.2.0 - '@img/sharp-libvips-darwin-x64': 1.2.0 - '@img/sharp-libvips-linux-arm': 1.2.0 - '@img/sharp-libvips-linux-arm64': 1.2.0 - '@img/sharp-libvips-linux-ppc64': 1.2.0 - '@img/sharp-libvips-linux-s390x': 1.2.0 - '@img/sharp-libvips-linux-x64': 1.2.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - '@img/sharp-linux-arm': 0.34.3 - '@img/sharp-linux-arm64': 0.34.3 - '@img/sharp-linux-ppc64': 0.34.3 - '@img/sharp-linux-s390x': 0.34.3 - '@img/sharp-linux-x64': 0.34.3 - '@img/sharp-linuxmusl-arm64': 0.34.3 - '@img/sharp-linuxmusl-x64': 0.34.3 - '@img/sharp-wasm32': 0.34.3 - '@img/sharp-win32-arm64': 0.34.3 - '@img/sharp-win32-ia32': 0.34.3 - '@img/sharp-win32-x64': 0.34.3 - optional: true - - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - - source-map-js@1.2.1: {} - - styled-jsx@5.1.6(react@18.3.1): - dependencies: - client-only: 0.0.1 - react: 18.3.1 - - tslib@2.8.1: {} - - undici-types@6.21.0: {} diff --git a/examples/demos/nextjs-ssr-demo/public/file.svg b/examples/demos/nextjs-ssr-demo/public/file.svg deleted file mode 100644 index 004145cdd..000000000 --- a/examples/demos/nextjs-ssr-demo/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/demos/nextjs-ssr-demo/public/globe.svg b/examples/demos/nextjs-ssr-demo/public/globe.svg deleted file mode 100644 index 567f17b0d..000000000 --- a/examples/demos/nextjs-ssr-demo/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/demos/nextjs-ssr-demo/public/next.svg b/examples/demos/nextjs-ssr-demo/public/next.svg deleted file mode 100644 index 5174b28c5..000000000 --- a/examples/demos/nextjs-ssr-demo/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/demos/nextjs-ssr-demo/public/vercel.svg b/examples/demos/nextjs-ssr-demo/public/vercel.svg deleted file mode 100644 index 770539603..000000000 --- a/examples/demos/nextjs-ssr-demo/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/demos/nextjs-ssr-demo/public/window.svg b/examples/demos/nextjs-ssr-demo/public/window.svg deleted file mode 100644 index b2b2a44f6..000000000 --- a/examples/demos/nextjs-ssr-demo/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/ActiveLink.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/ActiveLink.tsx deleted file mode 100644 index 1c7d79aca..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/ActiveLink.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import type { ReactNode } from "react"; - -interface ActiveLinkProps { - href: string; - children: ReactNode; - className?: string; -} - -export default function ActiveLink({ - href, - children, - className = "", -}: ActiveLinkProps) { - const pathname = usePathname(); - const isActive = pathname === href; - - return ( - - {children} - - ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/MagicLinkForm.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/MagicLinkForm.tsx deleted file mode 100644 index 4c089b984..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/MagicLinkForm.tsx +++ /dev/null @@ -1,67 +0,0 @@ -"use client"; - -import { useRouter } from "next/navigation"; -import { useId, useState } from "react"; - -interface MagicLinkFormProps { - sendMagicLinkAction: (formData: FormData) => Promise<{ - redirect?: string; - error?: string; - }>; - showDisplayName?: boolean; - buttonLabel?: string; -} - -export default function MagicLinkForm({ - sendMagicLinkAction, - showDisplayName = false, - buttonLabel = "Sign in with Magic Link", -}: MagicLinkFormProps) { - const [error, setError] = useState(null); - const router = useRouter(); - const displayNameId = useId(); - const emailId = useId(); - - const handleSubmit = async (formData: FormData) => { - try { - const result = await sendMagicLinkAction(formData); - - if (result.redirect) { - router.push(result.redirect); - } else if (result.error) { - setError(result.error); - } - } catch (err: unknown) { - setError( - err instanceof Error ? err.message : "Failed to send magic link", - ); - } - }; - - return ( -
- {showDisplayName && ( -
- - -
- )} - -
- - -
- - {error &&
{error}
} - - -
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/Navigation.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/Navigation.tsx deleted file mode 100644 index 59d0dced4..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/Navigation.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { createNhostClient } from "../lib/nhost/server"; -import ActiveLink from "./ActiveLink"; -import SignOutButton from "./SignOutButton"; - -export default async function Navigation() { - const nhost = await createNhostClient(); - const session = nhost.getUserSession(); - - return ( - - ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/SecurityKeyClient.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/SecurityKeyClient.tsx deleted file mode 100644 index 411610c06..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/SecurityKeyClient.tsx +++ /dev/null @@ -1,351 +0,0 @@ -"use client"; - -import { startRegistration } from "@simplewebauthn/browser"; -import { useRouter } from "next/navigation"; -import { useEffect, useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; -import { isWebAuthnSupported } from "../lib/utils"; - -/** - * Represents a WebAuthn security key stored for a user - */ -interface SecurityKey { - id: string; - credentialId: string; - nickname: string | null; -} - -interface SecurityKeyClientProps { - initialSecurityKeys: SecurityKey[]; - serverError: string | null; -} - -export default function SecurityKeyClient({ - initialSecurityKeys, - serverError, -}: SecurityKeyClientProps) { - const router = useRouter(); - const { nhost } = useAuth(); - const [securityKeys, setSecurityKeys] = - useState(initialSecurityKeys); - const [isRegistering, setIsRegistering] = useState(false); - const [isDeleting, setIsDeleting] = useState(false); - const [deletingKeyId, setDeletingKeyId] = useState(null); - const [keyName, setKeyName] = useState(""); - const [success, setSuccess] = useState(null); - const [errorMessage, setErrorMessage] = useState(serverError); - const [showAddForm, setShowAddForm] = useState(false); - const [isWebAuthnAvailable, setIsWebAuthnAvailable] = useState(false); - const keyNameId = useId(); - - // Check WebAuthn support after component mounts to prevent hydration mismatch - useEffect(() => { - setIsWebAuthnAvailable(isWebAuthnSupported()); - }, []); - - const deleteSecurityKey = async (keyId: string) => { - if (isDeleting) return; - - setIsDeleting(true); - setDeletingKeyId(keyId); - setSuccess(null); - setErrorMessage(null); - - try { - // Send request to server to delete the security key - await nhost.graphql.request({ - query: ` - mutation DeleteSecurityKey($keyId: uuid!) { - deleteAuthUserSecurityKey(id: $keyId) { - id - } - } - `, - variables: { - keyId, - }, - }); - - // Update the UI by removing the key from local state - setSecurityKeys(securityKeys.filter((key) => key.id !== keyId)); - setSuccess( - "Security key deleted successfully! Remember to also remove it from your authenticator app, password manager, or device credential manager to avoid future authentication issues.", - ); - - // Refresh the page to get updated data from server - router.refresh(); - - // Hide success message after 5 seconds - setTimeout(() => { - setSuccess(null); - }, 5000); - } catch (err) { - const error = err as Error; - setErrorMessage(`Failed to delete security key: ${error.message}`); - } finally { - setIsDeleting(false); - setDeletingKeyId(null); - } - }; - - const registerNewSecurityKey = async (e: React.FormEvent) => { - e.preventDefault(); - - // Check if browser supports WebAuthn - if (!isWebAuthnAvailable) { - setErrorMessage( - "WebAuthn is not supported by your browser. Please use a modern browser that supports WebAuthn.", - ); - return; - } - - // Validate key name exists - if (!keyName.trim()) { - setErrorMessage("Please provide a name for your security key"); - return; - } - - setIsRegistering(true); - setErrorMessage(null); - setSuccess(null); - - try { - // Step 1: Request challenge from server - // userId is implicitly used by the nhost client for authentication - const initResponse = await nhost.auth.addSecurityKey(); - - // Step 2: Browser prompts user for security key or biometric verification - const credential = await startRegistration({ - optionsJSON: initResponse.body, - }); - - if (!credential) { - setErrorMessage("No credential was selected. Please try again."); - return; - } - - // Step 3: Send credential public key back to server for verification - // userId is implicitly used by the nhost client for this operation - await nhost.auth.verifyAddSecurityKey({ - credential, - nickname: keyName.trim(), - }); - - // Step 4: Registration successful - update UI - setSuccess("Security key registered successfully!"); - setKeyName(""); - setShowAddForm(false); - - // Refresh the page to get updated data from server - router.refresh(); - } catch (err) { - const error = err as Error; - setErrorMessage(`Failed to register security key: ${error.message}`); - } finally { - setIsRegistering(false); - } - }; - - const toggleAddForm = () => { - setShowAddForm(!showAddForm); - setErrorMessage(null); - setSuccess(null); - setKeyName(""); - }; - - // Use client-side only rendering for browser-specific components - const [isMounted, setIsMounted] = useState(false); - - useEffect(() => { - setIsMounted(true); - }, []); - - return ( -
-

Security Keys

- - {errorMessage && ( -
{errorMessage}
- )} - - {success &&
{success}
} - - {isMounted && !isWebAuthnAvailable && ( -
-

- WebAuthn not supported! Your browser or device - doesn't support WebAuthn authentication. Please use a modern - browser (Chrome, Firefox, Safari, Edge) that supports WebAuthn. -

-

- Note: Even if your browser supports WebAuthn, you may need a - compatible authenticator like a fingerprint reader, facial - recognition, or a security key (e.g., YubiKey). -

-
- )} - - {showAddForm ? ( -
-

- Enter a name for your security key and follow the prompts from your - browser to register it. -

-

- Note: You'll need a security key (like YubiKey) or a device - with biometric authentication (like Touch ID, Face ID, or Windows - Hello). If registration fails, make sure your device has the - required capabilities. -

- -
-
- - setKeyName(e.target.value)} - placeholder="e.g., My YubiKey, Touch ID, Windows Hello" - disabled={isRegistering} - required - /> -
-
- - -
-
-
- ) : ( -
-

- Security Keys (WebAuthn) provide a secure passwordless - authentication option using hardware security keys, fingerprints, or - facial recognition. -

- - {/* List of existing security keys */} - {securityKeys.length === 0 ? ( -

No security keys registered.

- ) : ( -
-
    - {securityKeys.map((key) => ( -
  • -
    - - {key.nickname || "Unnamed key"} - - - ID: {key.credentialId.slice(0, 8)}... - -
    - -
  • - ))} -
-
- )} - - -
- )} -
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/SignOutButton.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/SignOutButton.tsx deleted file mode 100644 index 8f8577504..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/SignOutButton.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { signOut } from "../lib/auth/actions"; - -export default function SignOutButton() { - return ( -
-
- -
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/SocialSignIn.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/SocialSignIn.tsx deleted file mode 100644 index a12a31dee..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/SocialSignIn.tsx +++ /dev/null @@ -1,62 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { getProviderSignInUrl } from "../signin/actions"; - -interface SocialSignInProps { - provider: "github"; - disabled?: boolean; - label?: string; - className?: string; -} - -export default function SocialSignIn({ - provider, - disabled = false, - label = `Continue with ${provider.charAt(0).toUpperCase() + provider.slice(1)}`, - className = "btn btn-secondary w-full flex items-center justify-center gap-2", -}: SocialSignInProps) { - const [isLoading, setIsLoading] = useState(false); - - const handleSignIn = async () => { - setIsLoading(true); - try { - const result = await getProviderSignInUrl(provider); - - if (result.url) { - // Redirect to the provider's auth page - window.location.href = result.url; - } else if (result.error) { - console.error(result.error); - } - } catch (error) { - console.error("Failed to initiate social sign in:", error); - } finally { - setIsLoading(false); - } - }; - - return ( - - ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/TabForm.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/TabForm.tsx deleted file mode 100644 index f5d9ae42e..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/TabForm.tsx +++ /dev/null @@ -1,75 +0,0 @@ -"use client"; - -import { type ReactNode, useState } from "react"; - -interface TabFormProps { - passwordTabLabel?: string; - magicTabLabel?: string; - socialTabLabel?: string; - webauthnTabLabel?: string; - passwordTabContent: ReactNode; - magicTabContent: ReactNode; - socialTabContent?: ReactNode; - webauthnTabContent?: ReactNode; -} - -export default function TabForm({ - passwordTabLabel = "Email & Password", - magicTabLabel = "Magic Link", - socialTabLabel = "Social", - webauthnTabLabel = "Security Key", - passwordTabContent, - magicTabContent, - socialTabContent, - webauthnTabContent, -}: TabFormProps) { - const [activeTab, setActiveTab] = useState< - "password" | "magic" | "social" | "webauthn" - >("password"); - - return ( -
-
- - - {socialTabContent && ( - - )} - {webauthnTabContent && ( - - )} -
- -
- {activeTab === "password" && passwordTabContent} - {activeTab === "magic" && magicTabContent} - {activeTab === "social" && socialTabContent} - {activeTab === "webauthn" && webauthnTabContent} -
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/WebAuthnSignInForm.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/WebAuthnSignInForm.tsx deleted file mode 100644 index d3194902b..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/WebAuthnSignInForm.tsx +++ /dev/null @@ -1,127 +0,0 @@ -"use client"; - -import type { PublicKeyCredentialRequestOptions } from "@nhost/nhost-js/auth"; -import { startAuthentication } from "@simplewebauthn/browser"; -import { useRouter } from "next/navigation"; -import { useState } from "react"; -import { isWebAuthnSupported } from "../lib/utils"; -import { signInWebauthn, verifySignInWebauthn } from "../signin/actions"; - -interface WebAuthnSignInFormProps { - buttonLabel?: string; -} - -export default function WebAuthnSignInForm({ - buttonLabel = "Sign In with Security Key", -}: WebAuthnSignInFormProps) { - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [challengeData, setChallengeData] = - useState(null); - const router = useRouter(); - - /** - * Handles the WebAuthn authentication flow: - * 1. Request a challenge from the server - * 2. Have the browser/authenticator sign the challenge with the private key - * 3. Verify the signature on the server and establish a session - */ - const startWebAuthnSignIn = async (e: React.FormEvent) => { - e.preventDefault(); - setIsLoading(true); - setError(null); - - try { - // Check if WebAuthn is supported on this browser - if (!isWebAuthnSupported()) { - setError("WebAuthn is not supported by your browser."); - setIsLoading(false); - return; - } - - // Step 1: Request a challenge from the server for credential discovery - const result = await signInWebauthn(); - - if (result.error) { - setError(result.error); - setIsLoading(false); - return; - } - - if (!result.publicKeyCredentialRequestOptions) { - setError("Failed to get authentication challenge from server"); - setIsLoading(false); - return; - } - - setChallengeData(result.publicKeyCredentialRequestOptions); - - try { - // Step 2: Browser prompts user for their security key or biometric verification - const credential = await startAuthentication({ - optionsJSON: result.publicKeyCredentialRequestOptions, - }); - - if (!credential) { - setError("No credential was selected."); - setIsLoading(false); - return; - } - - // Step 3: Send the signed challenge to the server for verification - // Use PublicKeyCredential's built-in serialization method - const verifyResult = await verifySignInWebauthn(credential); - - if (verifyResult.error) { - setError(verifyResult.error); - return; - } - - if (verifyResult.redirect) { - router.push(verifyResult.redirect); - } else { - setError("Authentication failed: No redirect URL returned"); - } - } catch (credError) { - setError( - `WebAuthn authentication failed: ${(credError as Error).message || "Unknown error"}`, - ); - } - } catch (err) { - setError( - `An error occurred during WebAuthn sign in: ${(err as Error).message || "Unknown error"}`, - ); - } finally { - setIsLoading(false); - } - }; - - return ( -
- {error &&
{error}
} - - - -
-

- You'll be prompted to use your device's security key (like - TouchID, FaceID, Windows Hello, or a USB security key) -

-

- Your browser will show available security keys that you've - previously registered. -

-
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/components/WebAuthnSignUpForm.tsx b/examples/demos/nextjs-ssr-demo/src/app/components/WebAuthnSignUpForm.tsx deleted file mode 100644 index e42b3feaf..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/components/WebAuthnSignUpForm.tsx +++ /dev/null @@ -1,185 +0,0 @@ -"use client"; - -import type { PublicKeyCredentialCreationOptions } from "@nhost/nhost-js/auth"; -import { startRegistration } from "@simplewebauthn/browser"; -import { useRouter } from "next/navigation"; -import { useId, useState } from "react"; -import { isWebAuthnSupported } from "../lib/utils"; -import { signUpWebauthn, verifySignUpWebauthn } from "../signup/actions"; - -interface WebAuthnSignUpFormProps { - buttonLabel?: string; -} - -export default function WebAuthnSignUpForm({ - buttonLabel = "Register with Security Key", -}: WebAuthnSignUpFormProps) { - const [email, setEmail] = useState(""); - const [displayName, setDisplayName] = useState(""); - const [keyNickname, setKeyNickname] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [challengeData, setChallengeData] = - useState(null); - const router = useRouter(); - - /** - * Handles the WebAuthn registration flow (sign up with security key/biometrics) - * - * The WebAuthn registration flow consists of: - * 1. Server generates a challenge and user verification requirements - * 2. Browser activates the authenticator and creates new credential key pair - * 3. The private key remains securely on the user's device - * 4. The public key and attestation are sent to the server for verification - * 5. Server stores the public key for future authentication attempts - */ - const startWebAuthnRegistration = async ( - e: React.FormEvent, - ) => { - e.preventDefault(); - setIsLoading(true); - setError(null); - - // Validate required fields - if (!email) { - setError("Email is required"); - setIsLoading(false); - return; - } - - // Check browser compatibility before proceeding - if (!isWebAuthnSupported()) { - setError("WebAuthn is not supported by your browser."); - setIsLoading(false); - return; - } - - try { - // Step 1: Request a registration challenge from the server - const result = await signUpWebauthn({ - email, - displayName: displayName || undefined, - }); - - if (result.error) { - setError(result.error); - setIsLoading(false); - return; - } - - if (!result.publicKeyCredentialCreationOptions) { - setError("Failed to get registration challenge from server"); - setIsLoading(false); - return; - } - - // Store the challenge data for UI feedback - setChallengeData(result.publicKeyCredentialCreationOptions); - - try { - // Step 2: Browser prompts user to create a new credential - const credential = await startRegistration({ - optionsJSON: result.publicKeyCredentialCreationOptions, - }); - - if (!credential) { - setError("No credential was created."); - setIsLoading(false); - return; - } - - // Step 3: Send the credential attestation to the server for verification - // Use PublicKeyCredential's built-in serialization method - const verifyResult = await verifySignUpWebauthn( - credential, - keyNickname || `Security Key for ${displayName || email}`, - ); - - if (verifyResult.error) { - setError(verifyResult.error); - return; - } - - if (verifyResult.redirect) { - router.push(verifyResult.redirect); - } else { - setError("Registration failed: No redirect URL returned"); - } - } catch (credError) { - setError( - `WebAuthn registration failed: ${(credError as Error).message || "Unknown error"}`, - ); - } - } catch (err) { - setError( - `An error occurred during WebAuthn sign up: ${(err as Error).message || "Unknown error"}`, - ); - } finally { - setIsLoading(false); - } - }; - - return ( -
-
- - setDisplayName(e.target.value)} - /> -
- -
- - setEmail(e.target.value)} - required - /> -
- -
- - setKeyNickname(e.target.value)} - placeholder="My Security Key" - /> -

- A friendly name for your security key -

-
- - {error &&
{error}
} - - - -
-

- You'll be prompted to use your device's security key (like - TouchID, FaceID, Windows Hello, or a USB security key) -

-

- When prompted, please complete the biometric verification or insert - and activate your security key to create your account. -

-
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/favicon.ico b/examples/demos/nextjs-ssr-demo/src/app/favicon.ico deleted file mode 100644 index 718d6fea4..000000000 Binary files a/examples/demos/nextjs-ssr-demo/src/app/favicon.ico and /dev/null differ diff --git a/examples/demos/nextjs-ssr-demo/src/app/globals.css b/examples/demos/nextjs-ssr-demo/src/app/globals.css deleted file mode 100644 index 341d1adb1..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/globals.css +++ /dev/null @@ -1,562 +0,0 @@ -/* Base styles */ -:root { - --background: #030712; - --foreground: #ffffff; - --card-bg: #111827; - --card-border: #1f2937; - --primary: #6366f1; - --primary-hover: #4f46e5; - --secondary: #10b981; - --secondary-hover: #059669; - --accent: #8b5cf6; - --accent-hover: #7c3aed; - --success: #22c55e; - --error: #ef4444; - --text-primary: #f9fafb; - --text-secondary: #d1d5db; - --text-muted: #9ca3af; - --border-color: rgba(31, 41, 55, 0.7); -} - -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - background: var(--background); - color: var(--foreground); - font-family: - var(--font-geist-sans, ui-sans-serif, system-ui, -apple-system), sans-serif; - line-height: 1.6; - min-height: 100vh; -} - -/* Layout */ -.flex { - display: flex; -} - -.flex-col { - flex-direction: column; -} - -.items-center { - align-items: center; -} - -.justify-center { - justify-content: center; -} - -.justify-between { - justify-content: space-between; -} - -.min-h-screen { - min-height: 100vh; -} - -.w-full { - width: 100%; -} - -.max-w-2xl { - max-width: 42rem; -} - -.mx-auto { - margin-left: auto; - margin-right: auto; -} - -.p-6 { - padding: 1.5rem; -} - -.p-8 { - padding: 2rem; -} - -.py-5 { - padding-top: 1.25rem; - padding-bottom: 1.25rem; -} - -.mb-6 { - margin-bottom: 1.5rem; -} - -.mb-4 { - margin-bottom: 1rem; -} - -.mt-4 { - margin-top: 1rem; -} - -.mr-8 { - margin-right: 2rem; -} - -.ml-2 { - margin-left: 0.5rem; -} - -.space-y-5 > * + * { - margin-top: 1.25rem; -} - -.space-x-4 > * + * { - margin-left: 1rem; -} - -/* Typography */ -h1, -h2, -h3 { - font-weight: bold; - line-height: 1.2; -} - -.text-3xl { - font-size: 1.875rem; -} - -.text-2xl { - font-size: 1.5rem; -} - -.text-xl { - font-size: 1.25rem; -} - -.text-lg { - font-size: 1.125rem; -} - -.text-sm { - font-size: 0.875rem; -} - -.text-xs { - font-size: 0.75rem; -} - -.font-bold { - font-weight: 700; -} - -.font-semibold { - font-weight: 600; -} - -.font-medium { - font-weight: 500; -} - -.text-center { - text-align: center; -} - -.gradient-text { - background: linear-gradient(to right, var(--primary), var(--accent)); - -webkit-background-clip: text; - background-clip: text; - color: transparent; -} - -/* Components */ -.glass-card { - background: rgba(17, 24, 39, 0.7); - backdrop-filter: blur(8px); - border: 1px solid var(--border-color); - border-radius: 0.5rem; - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2); -} - -.btn { - display: inline-block; - padding: 0.625rem 1rem; - font-weight: 500; - border-radius: 0.375rem; - transition: all 0.2s ease; - cursor: pointer; - text-align: center; - border: none; -} - -.btn-primary { - background-color: var(--primary); - color: white; -} - -.btn-primary:hover:not(:disabled) { - background-color: var(--primary-hover); - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1); -} - -.btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.btn-secondary { - background-color: var(--secondary); - color: white; -} - -.btn-secondary:hover:not(:disabled) { - background-color: var(--secondary-hover); -} - -.nav-link { - display: inline-block; - padding: 0.5rem 1rem; - border-radius: 0.375rem; - font-weight: 600; - font-size: 0.875rem; - transition: all 0.2s ease; - color: var(--text-secondary); - text-decoration: none; -} - -.nav-link:hover { - color: white; - background-color: rgba(31, 41, 55, 0.7); -} - -.nav-link.active { - background-color: var(--primary); - color: white; - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.3); -} - -input, -textarea, -select { - width: 100%; - padding: 0.625rem 0.75rem; - background-color: rgba(31, 41, 55, 0.8); - border: 1px solid var(--border-color); - color: white; - border-radius: 0.375rem; - transition: all 0.2s; -} - -input:focus, -textarea:focus, -select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2); -} - -label { - display: block; - margin-bottom: 0.25rem; - font-size: 0.875rem; - font-weight: 500; - color: var(--text-secondary); -} - -.alert { - padding: 0.75rem; - border-radius: 0.375rem; - margin-bottom: 1rem; -} - -.alert-error { - background-color: rgba(239, 68, 68, 0.2); - border: 1px solid rgba(239, 68, 68, 0.5); - color: white; -} - -.alert-success { - background-color: rgba(34, 197, 94, 0.2); - border: 1px solid rgba(34, 197, 94, 0.5); - color: white; -} - -/* Navigation */ -.navbar { - position: sticky; - top: 0; - z-index: 10; - background-color: rgba(17, 24, 39, 0.8); - backdrop-filter: blur(8px); - border-bottom: 1px solid var(--border-color); - padding: 1rem 0; - margin-bottom: 2rem; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); -} - -.navbar-container { - display: flex; - justify-content: space-between; - align-items: center; - max-width: 42rem; - margin: 0 auto; - padding: 0 1.5rem; -} - -.navbar-brand { - color: var(--primary); - font-weight: bold; - font-size: 1.125rem; - margin-right: 2rem; -} - -.navbar-links { - display: flex; - gap: 1rem; -} - -/* Tables */ -table { - width: 100%; - border-collapse: collapse; -} - -th { - text-align: left; - padding: 0.75rem 1rem; - font-size: 0.75rem; - text-transform: uppercase; - color: var(--text-secondary); - border-bottom: 1px solid var(--border-color); -} - -td { - padding: 0.75rem 1rem; - border-bottom: 1px solid var(--border-color); - font-size: 0.875rem; -} - -tr:hover { - background-color: rgba(31, 41, 55, 0.3); -} - -/* File upload styles */ -.file-upload { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 1.5rem; - border: 2px dashed rgba(99, 102, 241, 0.3); - border-radius: 0.5rem; - background-color: rgba(31, 41, 55, 0.3); - cursor: pointer; - transition: all 0.2s; - width: 100%; - min-height: 120px; - color: inherit; - font-family: inherit; - font-size: inherit; - text-align: center; -} - -.file-upload:hover { - border-color: var(--primary); -} - -/* Reset button styles when used as file-upload */ -button.file-upload { - background: rgba(31, 41, 55, 0.3); - color: var(--text-color); -} - -/* Footer */ -footer { - padding: 1.25rem 0; - border-top: 1px solid var(--border-color); - display: flex; - justify-content: center; - align-items: center; -} - -/* Link styles */ -a { - color: var(--primary); - text-decoration: none; - transition: color 0.2s; -} - -a:hover { - color: var(--primary-hover); - text-decoration: underline; -} - -/* Loading state */ -.loading-container { - display: flex; - justify-content: center; - align-items: center; - min-height: 50vh; -} - -/* Code blocks */ -pre { - background-color: rgba(31, 41, 55, 0.8); - padding: 1rem; - border-radius: 0.375rem; - overflow: auto; - font-family: var(--font-geist-mono, monospace); - border: 1px solid var(--border-color); - font-size: 0.875rem; - color: var(--text-secondary); -} - -/* Profile data */ -.profile-item { - padding-bottom: 0.75rem; - margin-bottom: 0.75rem; - border-bottom: 1px solid var(--border-color); -} - -.profile-item strong { - color: var(--text-secondary); -} - -.action-link { - color: var(--primary); - font-weight: 500; - margin-right: 0.75rem; - cursor: pointer; -} - -.action-link:hover { - color: var(--primary-hover); - text-decoration: underline; -} - -.action-link-danger { - color: var(--error); -} - -.action-link-danger:hover { - color: #f05252; -} - -/* Icon button */ -.icon-button { - background-color: transparent; - color: var(--primary); - width: 40px; - height: 40px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - border: none; - transition: all 0.2s; -} - -.icon-button:hover { - background-color: rgba(99, 102, 241, 0.1); - color: var(--primary-hover); -} - -.icon-button:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.icon-button svg { - width: 20px; - height: 20px; -} - -/* Table action icons */ -.table-actions { - display: flex; - gap: 8px; -} - -.action-icon { - background-color: transparent; - border: none; - width: 32px; - height: 32px; - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all 0.2s; - padding: 0; -} - -.action-icon svg { - width: 18px; - height: 18px; -} - -.action-icon:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.action-icon-view { - color: var(--primary); -} - -.action-icon-view:hover:not(:disabled) { - background-color: rgba(99, 102, 241, 0.1); - color: var(--primary-hover); -} - -.action-icon-delete { - color: var(--error); -} - -.action-icon-delete:hover:not(:disabled) { - background-color: rgba(239, 68, 68, 0.1); - color: #f05252; -} - -/* Tab styles */ -.tabs-container { - display: flex; - border-radius: 0.5rem; - overflow: hidden; - margin-bottom: 1.5rem; - border: 1px solid var(--border-color); -} - -.tab-button { - flex: 1; - padding: 0.75rem 1rem; - font-weight: 500; - transition: all 0.2s ease; - background-color: rgba(31, 41, 55, 0.5); - color: var(--text-secondary); -} - -.tab-button:hover:not(.tab-active) { - background-color: rgba(31, 41, 55, 0.8); - color: var(--text-primary); -} - -.tab-button.tab-active { - background-color: var(--primary); - color: white; - box-shadow: 0 0 0 1px rgba(99, 102, 241, 0.3); -} - -.tab-button:first-child { - border-top-left-radius: 0.5rem; - border-bottom-left-radius: 0.5rem; -} - -.tab-button:last-child { - border-top-right-radius: 0.5rem; - border-bottom-right-radius: 0.5rem; -} - -.tab-content { - margin-top: 1.5rem; -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/layout.tsx b/examples/demos/nextjs-ssr-demo/src/app/layout.tsx deleted file mode 100644 index 15e4fc3f2..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/layout.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; -import Navigation from "./components/Navigation"; -import { AuthProvider } from "./lib/nhost/AuthProvider"; - -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - -export const metadata: Metadata = { - title: "Nhost Next.js Demo", - description: "Next.js demo for Nhost SDK", -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - -
- -
{children}
-
-

- © {new Date().getFullYear()} Nhost Demo -

-
-
-
- - - ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/lib/auth/actions.ts b/examples/demos/nextjs-ssr-demo/src/app/lib/auth/actions.ts deleted file mode 100644 index ae686d428..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/lib/auth/actions.ts +++ /dev/null @@ -1,38 +0,0 @@ -"use server"; - -import { revalidatePath } from "next/cache"; -import { redirect } from "next/navigation"; -import { createNhostClient } from "../nhost/server"; - -/** - * Revalidates the specified path after authentication state changes - * This ensures that server components re-render with the new auth state - */ -export async function revalidateAfterAuthChange(path = "/") { - // Revalidate the specified path to refresh server components - revalidatePath(path); - return { success: true }; -} - -/** - * Signs out the current user using the Nhost client - * and redirects them to the homepage - */ -export async function signOut() { - // Get the server Nhost client - const nhost = await createNhostClient(); - const session = nhost.getUserSession(); - - if (session) { - // Sign out with the refresh token - await nhost.auth.signOut({ - refreshToken: session.refreshToken, - }); - } - - // Revalidate all paths to ensure server components re-render - revalidatePath("/"); - - // Redirect to the homepage - redirect("/"); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/lib/nhost/AuthProvider.tsx b/examples/demos/nextjs-ssr-demo/src/app/lib/nhost/AuthProvider.tsx deleted file mode 100644 index da1c0e5a8..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/lib/nhost/AuthProvider.tsx +++ /dev/null @@ -1,191 +0,0 @@ -"use client"; - -import { createClient, type NhostClient } from "@nhost/nhost-js"; -import type { Session } from "@nhost/nhost-js/auth"; -import { CookieStorage } from "@nhost/nhost-js/session"; -import { useRouter } from "next/navigation"; -import { - createContext, - type ReactNode, - useCallback, - useContext, - useEffect, - useMemo, - useRef, - useState, -} from "react"; - -/** - * Authentication context interface providing access to user session state and Nhost client. - * Used throughout the application to access authentication-related data and operations. - */ -interface AuthContextType { - /** Current authenticated user object, null if not authenticated */ - user: Session["user"] | null; - /** Current session object containing tokens and user data, null if no active session */ - session: Session | null; - /** Boolean indicating if user is currently authenticated */ - isAuthenticated: boolean; - /** Boolean indicating if authentication state is still loading */ - isLoading: boolean; - /** Nhost client instance for making authenticated requests */ - nhost: NhostClient; -} - -const AuthContext = createContext(null); - -interface AuthProviderProps { - children: ReactNode; -} - -/** - * AuthProvider component that provides authentication context to the Next.js application. - * - * This component handles: - * - Initializing the Nhost client with cookie-based session storage - * - Managing authentication state (user, session, loading, authenticated status) - * - Cross-tab session synchronization using sessionStorage.onChange events - * - Detecting middleware-driven session changes through refresh token monitoring - * - Page visibility and focus event handling to maintain session consistency - * - Server-side state synchronization via router.refresh() when sessions change - * - * Key features: - * - Uses CookieStorage for session persistence across server/client boundaries - * - Tracks refresh token changes to detect server-side session updates - * - Automatically refreshes page when session state changes from other sources - * - Provides reactive authentication state for client components - */ -export const AuthProvider = ({ children }: AuthProviderProps) => { - const [user, setUser] = useState(null); - const [session, setSession] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [isAuthenticated, setIsAuthenticated] = useState(false); - const lastRefreshTokenIdRef = useRef(null); - const router = useRouter(); - - // Initialize Nhost client with cookie-based storage for server/client session sharing - const nhost = useMemo( - () => - createClient({ - region: process.env["NHOST_REGION"] || "local", - subdomain: process.env["NHOST_SUBDOMAIN"] || "local", - storage: new CookieStorage({ - secure: process.env.NODE_ENV === "production", - sameSite: "lax", - }), - }), - [], - ); - - /** - * Handles session reload when refresh token changes. - * This detects when the session has been updated by middleware or other tabs. - * - * @param currentRefreshTokenId - The current refresh token ID to compare against stored value - */ - const reloadSession = useCallback( - (currentRefreshTokenId: string | null) => { - if (currentRefreshTokenId !== lastRefreshTokenIdRef.current) { - lastRefreshTokenIdRef.current = currentRefreshTokenId; - - // Update local authentication state to match current session - const currentSession = nhost.getUserSession(); - setUser(currentSession?.user || null); - setSession(currentSession); - setIsAuthenticated(!!currentSession); - - // Trigger Next.js page refresh to sync server-side state with client changes - router.refresh(); - } - }, - [nhost, router], - ); - - // Initialize authentication state and set up cross-tab session synchronization - useEffect(() => { - setIsLoading(true); - - // Load initial session state from Nhost client - const currentSession = nhost.getUserSession(); - setUser(currentSession?.user || null); - setSession(currentSession); - setIsAuthenticated(!!currentSession); - lastRefreshTokenIdRef.current = currentSession?.refreshTokenId ?? null; - setIsLoading(false); - - // Subscribe to session changes from other browser tabs - // This enables real-time synchronization when user signs in/out in another tab - const unsubscribe = nhost.sessionStorage.onChange((session) => { - reloadSession(session?.refreshTokenId ?? null); - }); - - return unsubscribe; - }, [nhost, reloadSession]); - - // Handle session changes from server-side middleware and page focus events - useEffect(() => { - /** - * Checks for session changes when page becomes visible or focused. - * This catches middleware-driven session updates that occur server-side. - */ - const checkSessionOnFocus = () => { - reloadSession(nhost.getUserSession()?.refreshTokenId ?? null); - }; - - // Monitor page visibility changes (tab switching, window minimizing) - document.addEventListener("visibilitychange", () => { - if (!document.hidden) { - checkSessionOnFocus(); - } - }); - - // Monitor window focus events (clicking back into the browser window) - window.addEventListener("focus", checkSessionOnFocus); - - // Cleanup event listeners on component unmount - return () => { - document.removeEventListener("visibilitychange", checkSessionOnFocus); - window.removeEventListener("focus", checkSessionOnFocus); - }; - }, [nhost, reloadSession]); - - const value: AuthContextType = { - user, - session, - isAuthenticated, - isLoading, - nhost, - }; - - return {children}; -}; - -/** - * Custom hook to access the authentication context. - * - * Must be used within a component wrapped by AuthProvider. - * Provides access to current user session, authentication state, and Nhost client. - * - * @throws {Error} When used outside of AuthProvider - * @returns {AuthContextType} Authentication context containing user, session, and client - * - * @example - * ```tsx - * function MyComponent() { - * const { user, isAuthenticated, nhost } = useAuth(); - * - * if (!isAuthenticated) { - * return
Please sign in
; - * } - * - * return
Welcome, {user?.displayName}!
; - * } - * ``` - */ -export const useAuth = (): AuthContextType => { - const context = useContext(AuthContext); - if (!context) { - throw new Error("useAuth must be used within an AuthProvider"); - } - return context; -}; diff --git a/examples/demos/nextjs-ssr-demo/src/app/lib/nhost/server/index.tsx b/examples/demos/nextjs-ssr-demo/src/app/lib/nhost/server/index.tsx deleted file mode 100644 index dd203521d..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/lib/nhost/server/index.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { createServerClient, type NhostClient } from "@nhost/nhost-js"; -import { DEFAULT_SESSION_KEY, type Session } from "@nhost/nhost-js/session"; -import { cookies } from "next/headers"; -import type { NextRequest, NextResponse } from "next/server"; - -const key = DEFAULT_SESSION_KEY; - -/** - * Creates an Nhost client for use in server components. - * - * We rely on the vanilla createClient method from the Nhost JS SDK and a SessionStorage - * customized to be able to retrieve the session from cookies in Next.js server components. - * - * IMPORTANT!!! We need to disable the auto-refresh token feature as we are handling it in - * the middleware and server components are not allowed to write to cookies. Any session - * refreshed in a server component will not be persisted and might lead to issues with the session. - * - */ -export async function createNhostClient(): Promise { - const cookieStore = await cookies(); - - const nhost = createServerClient({ - region: process.env["NHOST_REGION"] || "local", - subdomain: process.env["NHOST_SUBDOMAIN"] || "local", - storage: { - // storage compatible with Next.js server components - get: (): Session | null => { - const s = cookieStore.get(key)?.value || null; - if (!s) { - return null; - } - const session = JSON.parse(s) as Session; - return session; - }, - set: (value: Session) => { - cookieStore.set(key, JSON.stringify(value)); - }, - remove: () => { - cookieStore.delete(key); - }, - }, - }); - - return nhost; -} - -/** - * Middleware function to handle Nhost authentication and session management. - * - * This function is designed to be used in Next.js middleware to manage user sessions - * and refresh tokens. Refreshing the session needs to be done in the middleware - * to ensure that the session is always up-to-date an accessible by both server and client components. - * - * @param {NextRequest} request - The incoming Next.js request object - * @param {NextResponse} response - The outgoing Next.js response object - */ -export async function handleNhostMiddleware( - request: NextRequest, - response: NextResponse, -): Promise { - const nhost = createServerClient({ - region: process.env["NHOST_REGION"] || "local", - subdomain: process.env["NHOST_SUBDOMAIN"] || "local", - storage: { - // storage compatible with Next.js middleware - get: (): Session | null => { - const raw = request.cookies.get(key)?.value || null; - if (!raw) { - return null; - } - const session = JSON.parse(raw) as Session; - return session; - }, - set: (value: Session) => { - response.cookies.set({ - name: key, - value: JSON.stringify(value), - path: "/", - httpOnly: false, //if set to true we can't access it in the client - secure: process.env.NODE_ENV === "production", - sameSite: "lax", - maxAge: 60 * 60 * 24 * 30, // 30 days in seconds - }); - }, - remove: () => { - response.cookies.delete(key); - }, - }, - }); - - // we only want to refresh the session if the token will - // expire in the next 60 seconds - return await nhost.refreshSession(60); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/lib/utils.ts b/examples/demos/nextjs-ssr-demo/src/app/lib/utils.ts deleted file mode 100644 index 0b4778c87..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/lib/utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Format file size in a readable way -export function formatFileSize(bytes: number): string { - if (bytes === 0) return "0 Bytes"; - - const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; - const i = Math.floor(Math.log(bytes) / Math.log(1024)); - - return `${parseFloat((bytes / 1024 ** i).toFixed(2))} ${sizes[i]}`; -} - -/** - * Checks if WebAuthn (FIDO2) authentication is supported in the current browser - * - * WebAuthn requires: - * 1. A secure context (HTTPS or localhost) - * 2. The PublicKeyCredential API - * 3. The navigator.credentials API - * - * This function determines if the current environment can support passwordless - * authentication using security keys or platform authenticators (e.g., Touch ID, - * Face ID, Windows Hello, or FIDO security keys). - * - * Note: Even if this returns true, the user still needs to have an authenticator - * (biometric sensor, security key) available on their device. - * - * @returns {boolean} Whether WebAuthn is supported in the current environment - */ -export const isWebAuthnSupported = (): boolean => { - return ( - typeof window !== "undefined" && - !!window.PublicKeyCredential && - !!navigator.credentials - ); -}; diff --git a/examples/demos/nextjs-ssr-demo/src/app/page.tsx b/examples/demos/nextjs-ssr-demo/src/app/page.tsx deleted file mode 100644 index 9e6421db0..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/page.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { redirect } from "next/navigation"; -import { createNhostClient } from "./lib/nhost/server"; - -export default async function Home() { - // Check if user is already authenticated - const nhost = await createNhostClient(); - const session = nhost.getUserSession(); - - // Redirect based on authentication status - if (session) { - redirect("/profile"); - } - - redirect("/signin"); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/profile/change-password.tsx b/examples/demos/nextjs-ssr-demo/src/app/profile/change-password.tsx deleted file mode 100644 index fb8e63f00..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/profile/change-password.tsx +++ /dev/null @@ -1,113 +0,0 @@ -"use client"; - -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -export default function ChangePassword() { - const [newPassword, setNewPassword] = useState(""); - const [confirmPassword, setConfirmPassword] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(""); - const [success, setSuccess] = useState(false); - - const { nhost } = useAuth(); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - - // Reset states - setError(""); - setSuccess(false); - - // Validate passwords - if (newPassword.length < 3) { - setError("Password must be at least 3 characters long"); - return; - } - - if (newPassword !== confirmPassword) { - setError("Passwords do not match"); - return; - } - - setIsLoading(true); - - try { - await nhost.auth.changeUserPassword({ - newPassword, - }); - - setSuccess(true); - setNewPassword(""); - setConfirmPassword(""); - } catch (err) { - const error = err as FetchError; - setError(`Failed to change password: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - return ( -
-

Change Password

- - {success && ( -
- Password changed successfully! -
- )} - - {error &&
{error}
} - -
-
- - setNewPassword(e.target.value)} - className="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500" - required - minLength={3} - disabled={isLoading} - /> -
- -
- - setConfirmPassword(e.target.value)} - className="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500" - required - disabled={isLoading} - /> -
- - -
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/profile/mfa-settings.tsx b/examples/demos/nextjs-ssr-demo/src/app/profile/mfa-settings.tsx deleted file mode 100644 index bc1d72155..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/profile/mfa-settings.tsx +++ /dev/null @@ -1,292 +0,0 @@ -"use client"; - -import Image from "next/image"; -import { useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface MFASettingsProps { - initialMfaEnabled: boolean; -} - -export default function MFASettings({ initialMfaEnabled }: MFASettingsProps) { - const { nhost } = useAuth(); - const [isMfaEnabled, setIsMfaEnabled] = useState(initialMfaEnabled); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [success, setSuccess] = useState(null); - - // MFA setup states - const [isSettingUpMfa, setIsSettingUpMfa] = useState(false); - const [totpSecret, setTotpSecret] = useState(""); - const [qrCodeUrl, setQrCodeUrl] = useState(""); - const [verificationCode, setVerificationCode] = useState(""); - - // Disabling MFA states - const [isDisablingMfa, setIsDisablingMfa] = useState(false); - const [disableVerificationCode, setDisableVerificationCode] = useState(""); - - const verificationCodeId = useId(); - const disableVerificationCodeId = useId(); - - // Begin MFA setup process - const handleEnableMfa = async () => { - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Generate TOTP secret - const response = await nhost.auth.changeUserMfa(); - - if (response.body) { - setTotpSecret(response.body.totpSecret); - setQrCodeUrl(response.body.imageUrl); - setIsSettingUpMfa(true); - } - } catch (err) { - console.error("Error generating TOTP secret:", err); - setError("Failed to generate TOTP secret. Please try again."); - } finally { - setIsLoading(false); - } - }; - - // Verify TOTP and enable MFA - const handleVerifyTotp = async () => { - if (!verificationCode) { - setError("Please enter the verification code"); - return; - } - - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Verify and activate MFA - const response = await nhost.auth.verifyChangeUserMfa({ - activeMfaType: "totp", - code: verificationCode, - }); - - if (response.body) { - setIsMfaEnabled(true); - setIsSettingUpMfa(false); - setSuccess("MFA has been successfully enabled."); - } - } catch (err) { - console.error("Error verifying TOTP:", err); - setError( - "Failed to verify code. Please make sure you entered the correct code from your authenticator app.", - ); - } finally { - setIsLoading(false); - } - }; - - // Show disable MFA confirmation - const handleShowDisableMfa = () => { - setIsDisablingMfa(true); - setError(null); - setSuccess(null); - }; - - // Disable MFA - const handleDisableMfa = async () => { - if (!disableVerificationCode) { - setError("Please enter your verification code to confirm"); - return; - } - - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Disable MFA by setting activeMfaType to empty string - // We need to provide the current TOTP code to verify identity - const response = await nhost.auth.verifyChangeUserMfa({ - activeMfaType: "", - code: disableVerificationCode, - }); - - if (response.body) { - setIsMfaEnabled(false); - setIsDisablingMfa(false); - setDisableVerificationCode(""); - setSuccess("MFA has been successfully disabled."); - } - } catch (err) { - console.error("Error disabling MFA:", err); - setError( - "Failed to disable MFA. Please make sure you entered the correct verification code from your authenticator app.", - ); - } finally { - setIsLoading(false); - } - }; - - // Cancel MFA setup - const handleCancelMfaSetup = () => { - setIsSettingUpMfa(false); - setTotpSecret(""); - setQrCodeUrl(""); - setVerificationCode(""); - }; - - // Cancel MFA disable - const handleCancelMfaDisable = () => { - setIsDisablingMfa(false); - setDisableVerificationCode(""); - setError(null); - }; - - return ( -
-

Multi-Factor Authentication

- - {error &&
{error}
} - - {success &&
{success}
} - - {isSettingUpMfa ? ( -
-

- Scan this QR code with your authenticator app (e.g., Google - Authenticator, Authy): -

- - {qrCodeUrl && ( -
-
- TOTP QR Code -
-
- )} - -

Or manually enter this secret key:

-
- {totpSecret} -
- -
- - setVerificationCode(e.target.value)} - placeholder="Enter 6-digit code" - maxLength={6} - required - /> -
- -
- - - -
-
- ) : isDisablingMfa ? ( -
-

- To disable Multi-Factor Authentication, please enter the current - verification code from your authenticator app. -

- -
- - setDisableVerificationCode(e.target.value)} - placeholder="Enter 6-digit code" - maxLength={6} - required - /> -
- -
- - - -
-
- ) : ( -
-

- Multi-Factor Authentication adds an extra layer of security to your - account by requiring a verification code from your authenticator app - when signing in. -

- -
- Status: - - {isMfaEnabled ? "Enabled" : "Disabled"} - -
- - {isMfaEnabled ? ( - - ) : ( - - )} -
- )} -
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/profile/page.tsx b/examples/demos/nextjs-ssr-demo/src/app/profile/page.tsx deleted file mode 100644 index dba1949fe..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/profile/page.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { createNhostClient } from "../lib/nhost/server"; -import ChangePassword from "./change-password"; -import MFASettings from "./mfa-settings"; -import SecurityKeys from "./security-keys"; - -interface GetUserMfaStatusResponse { - user: { - activeMfaType: string | null; - }; -} - -export default async function Profile() { - // Create the client with async cookie access - const nhost = await createNhostClient(); - const session = nhost.getUserSession(); - - // Determine if MFA is enabled for the user by querying the activeMfaType - let isMfaEnabled = false; - - if (session?.user?.id) { - try { - const response = await nhost.graphql.request({ - query: ` - query GetUserMfaStatus($userId: uuid!) { - user(id: $userId) { - activeMfaType - } - } - `, - variables: { - userId: session.user.id, - }, - }); - - // MFA is enabled if activeMfaType is "totp" - isMfaEnabled = response.body.data?.user?.activeMfaType === "totp"; - - if (response.body.errors && response.body.errors.length > 0) { - console.error("Error fetching MFA status:", response.body.errors); - } - } catch (err) { - console.error("Failed to query MFA status:", err); - } - } - - return ( -
-

Your Profile

- -
-
-
- Display Name: - - {session?.user?.displayName || "Not set"} - -
- -
- Email: - - {session?.user?.email || "Not available"} - -
- -
- User ID: - - {session?.user?.id || "Not available"} - -
- -
- Roles: - - {session?.user?.roles?.join(", ") || "None"} - -
- -
- Email Verified: - - {session?.user?.emailVerified ? "Yes" : "No"} - -
-
-
- -
-

Session Information

-
{JSON.stringify(session, null, 2)}
-
- - {/* MFA Settings Component */} - - - {/* Security Keys Component */} - - - {/* Change Password Component */} - -
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/profile/security-keys.tsx b/examples/demos/nextjs-ssr-demo/src/app/profile/security-keys.tsx deleted file mode 100644 index f016864f0..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/profile/security-keys.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { Suspense } from "react"; -import SecurityKeyClient from "../components/SecurityKeyClient"; -import { createNhostClient } from "../lib/nhost/server"; - -/** - * Represents a WebAuthn security key stored for a user - */ -interface SecurityKey { - id: string; - credentialId: string; - nickname: string | null; -} - -/** - * GraphQL response format for security keys query - */ -interface SecurityKeysData { - authUserSecurityKeys: SecurityKey[]; -} - -export default async function SecurityKeys() { - // Initialize the server-side Nhost client - const nhost = await createNhostClient(); - - // Get the current session - const session = nhost.getUserSession(); - - // Default values for when not authenticated or when data can't be fetched - let securityKeys: SecurityKey[] = []; - let isLoading = false; - let error: string | null = null; - - if (session) { - isLoading = true; - - try { - // Server-side fetch of security keys - const response = await nhost.graphql.request({ - query: ` - query GetUserSecurityKeys { - authUserSecurityKeys { - id - credentialId - nickname - } - } - `, - }); - - // Extract security keys from the response - if (response.body.data?.authUserSecurityKeys) { - securityKeys = response.body.data.authUserSecurityKeys; - } - isLoading = false; - } catch (err: unknown) { - error = `Failed to fetch security keys: ${err instanceof Error ? err.message : String(err)}`; - console.error(error); - isLoading = false; - } - } - - // If still loading or not authenticated, show appropriate message - if (!session) { - return ( -
-

Security Keys

-

You must be signed in to manage your security keys.

-
- ); - } - - if (isLoading) { - return ( -
-

Security Keys

-

Loading security keys...

-
- ); - } - - // Render the client component with the server-fetched data - // Wrap in Suspense to handle any potential async rendering issues - return ( - -

Security Keys

-

Loading security keys...

- - } - > - -
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signin/SignInForm.tsx b/examples/demos/nextjs-ssr-demo/src/app/signin/SignInForm.tsx deleted file mode 100644 index 539aa5dc6..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signin/SignInForm.tsx +++ /dev/null @@ -1,54 +0,0 @@ -"use client"; - -import { useRouter } from "next/navigation"; -import { useId, useState } from "react"; -import { signIn } from "./actions"; - -interface SignInFormProps { - initialError?: string; -} - -export default function SignInForm({ initialError }: SignInFormProps) { - const [error, setError] = useState(initialError); - const router = useRouter(); - - const handleSubmit = async (formData: FormData) => { - try { - const result = await signIn(formData); - - if (result.redirect) { - router.push(result.redirect); - } else if (result.error) { - setError(result.error); - } - } catch (err: unknown) { - setError( - err instanceof Error ? err.message : "An error occurred during sign in", - ); - } - }; - - return ( -
-
- - -
- -
- - -
- - {error && ( -
- {typeof error === "string" ? error : "Sign in failed"} -
- )} - - -
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signin/actions.ts b/examples/demos/nextjs-ssr-demo/src/app/signin/actions.ts deleted file mode 100644 index d6c773c9f..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signin/actions.ts +++ /dev/null @@ -1,226 +0,0 @@ -"use server"; - -import type { - CredentialAssertionResponse, - ErrorResponse, -} from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { revalidatePath } from "next/cache"; -import { createNhostClient } from "../lib/nhost/server"; - -/** - * Signs in a user with email and password - */ -export async function signIn(formData: FormData) { - const email = formData.get("email") as string; - const password = formData.get("password") as string; - - // Validate inputs - if (!email || !password) { - return { error: "Email and password are required" }; - } - - try { - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Sign in with email and password - const response = await nhost.auth.signInEmailPassword({ - email, - password, - }); - - // Check if MFA is required - if (response.body.mfa) { - // Return redirect URL for MFA - return { redirect: `/signin/mfa?ticket=${response.body.mfa.ticket}` }; - } - - // If we have a session, sign in was successful - if (response.body.session) { - // Revalidate all paths to ensure server components re-render - revalidatePath("/"); - - // Return redirect to profile page - return { redirect: "/profile" }; - } - - // If we got here, something went wrong - return { error: "Failed to sign in: unexpected error" }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to sign in: ${error.message}`, - }; - } -} - -/** - * Verifies MFA code for sign in - */ -export async function verifyMfa(formData: FormData) { - const otp = formData.get("otp") as string; - const ticket = formData.get("ticket") as string; - - // Validate inputs - if (!otp || !ticket) { - return { error: "Verification code and ticket are required" }; - } - - try { - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Verify MFA code - const response = await nhost.auth.verifySignInMfaTotp({ - ticket, - otp, - }); - - // If we have a session, verification was successful - if (response.body.session) { - // Revalidate all paths to ensure server components re-render - revalidatePath("/"); - - // Return redirect to profile page - return { redirect: "/profile" }; - } - - // If we got here, something went wrong - return { error: "Failed to verify MFA code", ticket }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to verify MFA code: ${error.message}`, - ticket, - }; - } -} - -/** - * Sends a magic link to the provided email - */ -export async function sendMagicLink(formData: FormData) { - const email = formData.get("email") as string; - const displayName = (formData.get("displayName") as string) || undefined; - - // Validate inputs - if (!email) { - return { error: "Email is required" }; - } - - try { - // Get origin for redirect URL - const origin = - process.env["NEXT_PUBLIC_APP_URL"] || "http://localhost:3000"; - - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Send magic link - const response = await nhost.auth.signInPasswordlessEmail({ - email, - options: { - displayName, - redirectTo: `${origin}/verify`, - }, - }); - - if (response.body) { - return { redirect: "/signin?magic=success" }; - } - - // If we got here, something went wrong - return { error: "Failed to send magic link" }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to sign in: ${error.message}`, - }; - } -} - -/** - * Gets the URL for social provider sign in - */ -export async function getProviderSignInUrl(provider: "github") { - try { - // Get origin for redirect URL - const origin = - process.env["NEXT_PUBLIC_APP_URL"] || "http://localhost:3000"; - const redirectTo = `${origin}/verify`; - - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Get provider URL - const url = nhost.auth.signInProviderURL(provider, { - redirectTo, - }); - - return { url }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to create provider URL: ${error.message}`, - }; - } -} - -/** - * Initiates WebAuthn sign in process - * Server side function that gets authentication options from Nhost - */ -export async function signInWebauthn() { - try { - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Request authentication options from server - const response = await nhost.auth.signInWebauthn({}); - - // Return the challenge data for the client - return { - publicKeyCredentialRequestOptions: response.body, - }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to initiate WebAuthn sign in: ${error.message}`, - }; - } -} - -/** - * Verifies WebAuthn authentication response - * This is called after the user has completed the WebAuthn authentication - */ -export async function verifySignInWebauthn( - credential: CredentialAssertionResponse, -) { - try { - // Get the server Nhost client - const nhost = await createNhostClient(); - - const response = await nhost.auth.verifySignInWebauthn({ - credential, - }); - - // If we have a session, verification was successful - if (response.body?.session) { - // Revalidate all paths to ensure server components re-render - revalidatePath("/"); - - // Return redirect to profile page - return { redirect: "/profile" }; - } - - // If we got here, something went wrong - return { error: "Failed to verify WebAuthn authentication" }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to verify WebAuthn authentication: ${error.message}`, - }; - } -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/MfaVerificationForm.tsx b/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/MfaVerificationForm.tsx deleted file mode 100644 index c57c96379..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/MfaVerificationForm.tsx +++ /dev/null @@ -1,71 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useId, useState } from "react"; -import { verifyMfa } from "../actions"; - -interface MfaVerificationFormProps { - ticket: string; - initialError?: string; -} - -export default function MfaVerificationForm({ - ticket, - initialError, -}: MfaVerificationFormProps) { - const [error, setError] = useState(initialError); - const router = useRouter(); - - const handleSubmit = async (formData: FormData) => { - try { - const result = await verifyMfa(formData); - - if (result.redirect) { - router.push(result.redirect); - } else if (result.error) { - setError(result.error); - } - } catch (err: unknown) { - setError( - err instanceof Error - ? err.message - : "An error occurred during verification", - ); - } - }; - - return ( -
- - -
- - -
- - {error && ( -
- {typeof error === "string" ? error : "Verification failed"} -
- )} - -
- - - - Back - -
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/actions.ts b/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/actions.ts deleted file mode 100644 index d5e31746d..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/actions.ts +++ /dev/null @@ -1,49 +0,0 @@ -"use server"; - -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { revalidatePath } from "next/cache"; -import { redirect } from "next/navigation"; -import { createNhostClient } from "../../lib/nhost/server"; - -/** - * Verifies MFA code for sign in - */ -export async function verifyMfa(formData: FormData): Promise { - const otp = formData.get("otp") as string; - const ticket = formData.get("ticket") as string; - - // Validate inputs - if (!otp || !ticket) { - redirect("/signin/mfa?error=Verification+code+and+ticket+are+required"); - } - - try { - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Verify MFA code - const response = await nhost.auth.verifySignInMfaTotp({ - ticket, - otp, - }); - - // If we have a session, verification was successful - if (response.body.session) { - // Revalidate all paths to ensure server components re-render - revalidatePath("/"); - - // Redirect to profile page - redirect("/profile"); - } - - // If we got here, something went wrong - redirect(`/signin/mfa?ticket=${ticket}&error=Failed+to+verify+MFA+code`); - } catch (err) { - const error = err as FetchError; - const errorMessage = `Failed to verify MFA code: ${error.message}`; - redirect( - `/signin/mfa?ticket=${ticket}&error=${encodeURIComponent(errorMessage)}`, - ); - } -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/page.tsx b/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/page.tsx deleted file mode 100644 index 9b196c06a..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signin/mfa/page.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { redirect } from "next/navigation"; -import { createNhostClient } from "../../lib/nhost/server"; -import MfaVerificationForm from "./MfaVerificationForm"; - -export default async function MfaVerification({ - searchParams, -}: { - searchParams: Promise<{ ticket?: string; error?: string }>; -}) { - // Extract ticket and error from URL - const params = await searchParams; - const ticket = params.ticket; - const error = params.error; - - // Check if user is already authenticated - const nhost = await createNhostClient(); - const session = nhost.getUserSession(); - - // If user is already authenticated, redirect to profile - if (session) { - redirect("/profile"); - } - - // If no ticket is provided, redirect to sign in - if (!ticket) { - redirect("/signin"); - } - - return ( -
-

Nhost SDK Demo

- -
-

Verification Required

- -
-

- A verification code is required to complete sign in. Please enter - the code from your authenticator app. -

- - -
-
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signin/page.tsx b/examples/demos/nextjs-ssr-demo/src/app/signin/page.tsx deleted file mode 100644 index b2d7fb8ac..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signin/page.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import Link from "next/link"; -import MagicLinkForm from "../components/MagicLinkForm"; -import SocialSignIn from "../components/SocialSignIn"; -import TabForm from "../components/TabForm"; -import WebAuthnSignInForm from "../components/WebAuthnSignInForm"; -import { sendMagicLink } from "./actions"; -import SignInForm from "./SignInForm"; - -export default async function SignIn({ - searchParams, -}: { - searchParams: Promise<{ error?: string; magic?: string }>; -}) { - // Extract error and magic link status from URL - const params = await searchParams; - const error = params?.error; - const magicLinkSent = params?.magic === "success"; - - return ( -
-

Nhost SDK Demo

- -
-

Sign In

- - {magicLinkSent ? ( -
-

- Magic link sent! Check your email to sign in. -

- - Back to sign in - -
- ) : ( - } - magicTabContent={ -
- -
- } - socialTabContent={ -
-

Sign in using your Social account

- -
- } - webauthnTabContent={ - - } - /> - )} -
- -
-

- Don't have an account? Sign Up -

-
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signup/SignUpForm.tsx b/examples/demos/nextjs-ssr-demo/src/app/signup/SignUpForm.tsx deleted file mode 100644 index ad495514a..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signup/SignUpForm.tsx +++ /dev/null @@ -1,59 +0,0 @@ -"use client"; - -import { useRouter } from "next/navigation"; -import { useId, useState } from "react"; -import { signUp } from "./actions"; - -interface SignUpFormProps { - initialError?: string; -} - -export default function SignUpForm({ initialError }: SignUpFormProps) { - const [error, setError] = useState(initialError); - const router = useRouter(); - - const handleSubmit = async (formData: FormData) => { - try { - const result = await signUp(formData); - - if (result.redirect) { - router.push(result.redirect); - } else if (result.error) { - setError(result.error); - } - } catch (err: unknown) { - setError( - err instanceof Error ? err.message : "An error occurred during sign up", - ); - } - }; - - return ( -
-
- - -
- -
- - -
- -
- - -
- - {error && ( -
- {typeof error === "string" ? error : "Sign up failed"} -
- )} - - -
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signup/actions.ts b/examples/demos/nextjs-ssr-demo/src/app/signup/actions.ts deleted file mode 100644 index f3297606d..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signup/actions.ts +++ /dev/null @@ -1,183 +0,0 @@ -"use server"; - -import type { - CredentialCreationResponse, - ErrorResponse, -} from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { revalidatePath } from "next/cache"; -import { createNhostClient } from "../lib/nhost/server"; - -/** - * Signs up a user with email and password - */ -export async function signUp(formData: FormData) { - const email = formData.get("email") as string; - const password = formData.get("password") as string; - const displayName = formData.get("displayName") as string; - - // Validate inputs - if (!email || !password || !displayName) { - return { error: "All fields are required" }; - } - - try { - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Get origin for redirect URL - const origin = - process.env["NEXT_PUBLIC_APP_URL"] || "http://localhost:3000"; - - // Sign up with email and password - const response = await nhost.auth.signUpEmailPassword({ - email, - password, - options: { - displayName, - redirectTo: `${origin}/verify`, - }, - }); - - // If we have a session, sign up was successful - if (response.body.session) { - // Revalidate all paths to ensure server components re-render - revalidatePath("/"); - - // Return redirect to profile page - return { redirect: "/profile" }; - } - - // If no session but no error, email verification was sent - if (response.body) { - return { - redirect: `/signup?verify=success&email=${encodeURIComponent(email)}`, - }; - } - - // If we got here, something went wrong - return { error: "Failed to sign up" }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to sign up: ${error.message}`, - }; - } -} - -/** - * Sends a magic link to the provided email for signup - */ -export async function sendMagicLink(formData: FormData) { - const email = formData.get("email") as string; - const displayName = (formData.get("displayName") as string) || undefined; - - // Validate inputs - if (!email) { - return { error: "Email is required" }; - } - - try { - // Get origin for redirect URL - const origin = - process.env["NEXT_PUBLIC_APP_URL"] || "http://localhost:3000"; - - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Send magic link - const response = await nhost.auth.signInPasswordlessEmail({ - email, - options: { - displayName, - redirectTo: `${origin}/verify`, - }, - }); - - if (response.body) { - return { redirect: "/signup?magic=success" }; - } - - // If we got here, something went wrong - return { error: "Failed to send magic link" }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to send magic link: ${error.message}`, - }; - } -} - -/** - * Initiates WebAuthn registration process (sign up) - */ -export async function signUpWebauthn({ - email, - displayName, -}: { - email: string; - displayName?: string; -}) { - // Validate inputs - if (!email) { - return { error: "Email is required" }; - } - - try { - // Get the server Nhost client - const nhost = await createNhostClient(); - - // Request registration options from server - const response = await nhost.auth.signUpWebauthn({ - email, - options: { - displayName, - }, - }); - - // Return the challenge data for the client - return { - publicKeyCredentialCreationOptions: response.body, - }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to initiate WebAuthn sign up: ${error.message}`, - }; - } -} - -/** - * Verifies WebAuthn registration response - */ -export async function verifySignUpWebauthn( - credential: CredentialCreationResponse, - nickname: string, -) { - try { - // Get the server Nhost client - const nhost = await createNhostClient(); - - const response = await nhost.auth.verifySignUpWebauthn({ - credential, - nickname, - }); - - // If we have a session, verification was successful - if (response.body?.session) { - // Revalidate all paths to ensure server components re-render - revalidatePath("/"); - - // Return redirect to profile page - return { redirect: "/profile" }; - } - - // If we got here, something went wrong - return { error: "Failed to verify WebAuthn registration" }; - } catch (err) { - const error = err as FetchError; - return { - error: `Failed to verify WebAuthn registration: ${error.message}`, - }; - } -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/signup/page.tsx b/examples/demos/nextjs-ssr-demo/src/app/signup/page.tsx deleted file mode 100644 index 257675f96..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/signup/page.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import Link from "next/link"; -import MagicLinkForm from "../components/MagicLinkForm"; -import SocialSignIn from "../components/SocialSignIn"; -import TabForm from "../components/TabForm"; -import WebAuthnSignUpForm from "../components/WebAuthnSignUpForm"; -import { sendMagicLink } from "./actions"; -import SignUpForm from "./SignUpForm"; - -export default async function SignUp({ - searchParams, -}: { - searchParams: Promise<{ - error?: string; - magic?: string; - verify?: string; - email?: string; - }>; -}) { - // Extract error and magic link status from URL - const params = await searchParams; - const error = params?.error; - const magicLinkSent = params?.magic === "success"; - const verificationSent = params?.verify === "success"; - const email = params?.email; - - return ( -
-

Nhost SDK Demo

- -
- {verificationSent ? ( - <> -

Check Your Email

- -
-
-

- We've sent a verification link to {email} -

-

- Please check your email and click the verification link to - activate your account. -

-
- - - Back to Sign In - -
- - ) : ( - <> -

Sign Up

- - {magicLinkSent ? ( -
-

- Magic link sent! Check your email to sign in. -

- - Back to sign up - -
- ) : ( - } - magicTabContent={ -
- -
- } - socialTabContent={ -
-

Sign up using your Social account

- -
- } - webauthnTabContent={ - - } - /> - )} - - )} -
- -
-

- Already have an account? Sign In -

-
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/upload/client.tsx b/examples/demos/nextjs-ssr-demo/src/app/upload/client.tsx deleted file mode 100644 index a2defbb40..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/upload/client.tsx +++ /dev/null @@ -1,399 +0,0 @@ -"use client"; - -import type { FileMetadata } from "@nhost/nhost-js/storage"; -import { useRouter } from "next/navigation"; -import { type ChangeEvent, useRef, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; -import { formatFileSize } from "../lib/utils"; - -interface UploadClientProps { - initialFiles: FileMetadata[]; - serverError: string | null; -} - -export default function UploadClient({ - initialFiles, - serverError, -}: UploadClientProps) { - const { nhost } = useAuth(); - const router = useRouter(); - const fileInputRef = useRef(null); - - const [selectedFile, setSelectedFile] = useState(null); - const [uploading, setUploading] = useState(false); - const [uploadResult, setUploadResult] = useState(null); - const [error, setError] = useState(serverError); - const [files, setFiles] = useState(initialFiles); - const [viewingFile, setViewingFile] = useState(null); - const [deleting, setDeleting] = useState(null); - const [deleteStatus, setDeleteStatus] = useState<{ - message: string; - isError: boolean; - } | null>(null); - - // Function to handle viewing a file with proper authorization - const handleViewFile = async ( - fileId: string, - fileName: string, - mimeType: string, - ) => { - setViewingFile(fileId); - - try { - // Fetch the file with authentication using the SDK - const response = await nhost.storage.getFile(fileId); - - // Create a URL for the blob - const url = URL.createObjectURL(response.body); - - // Handle different file types appropriately - if ( - mimeType.startsWith("image/") || - mimeType === "application/pdf" || - mimeType.startsWith("text/") || - mimeType.startsWith("video/") || - mimeType.startsWith("audio/") - ) { - // For media types that browsers can display natively, just open in a new tab - window.open(url, "_blank"); - } else { - // For other file types, trigger download - const link = document.createElement("a"); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - - // Optional: Open a small window to inform the user about the download - const newWindow = window.open("", "_blank", "width=400,height=200"); - if (newWindow) { - newWindow.document.write(` - - - File Download - - - -

Downloading: ${fileName}

-

Your download has started. You can close this window.

- - - `); - newWindow.document.close(); - } - } - } catch (err) { - setError( - `Failed to view file: ${err instanceof Error ? err.message : "Unknown error"}`, - ); - console.error("Error viewing file:", err); - } finally { - setViewingFile(null); - } - }; - - const handleFileChange = (e: ChangeEvent) => { - if (e.target.files && e.target.files.length > 0) { - const file = e.target.files[0]; - if (file) { - setSelectedFile(file); - setError(null); - setUploadResult(null); - } - } - }; - - const handleUpload = async () => { - if (!selectedFile) { - setError("Please select a file to upload"); - return; - } - - setUploading(true); - setError(null); - - try { - // Upload file using Nhost storage - const response = await nhost.storage.uploadFiles({ - "bucket-id": "default", - "file[]": [selectedFile], - }); - - // Get the processed file data - const uploadedFile = response.body.processedFiles?.[0]; - setUploadResult(uploadedFile || null); - - // Reset form - setSelectedFile(null); - if (fileInputRef.current) { - fileInputRef.current.value = ""; - } - - if (!uploadedFile) { - setError("Failed to upload file"); - return; - } - setFiles((prevFiles) => [uploadedFile, ...prevFiles]); - - // Refresh page to get updated file list from server - router.refresh(); - - // Clear success message after 3 seconds - setTimeout(() => { - setUploadResult(null); - }, 3000); - } catch (err: unknown) { - setError(err instanceof Error ? err.message : "Failed to upload file"); - } finally { - setUploading(false); - } - }; - - // Function to handle deleting a file - const handleDeleteFile = async (fileId: string) => { - if (!fileId || deleting) return; - - setDeleting(fileId); - setError(null); - setDeleteStatus(null); - - // Get the file name for the status message - const fileToDelete = files.find((file) => file.id === fileId); - const fileName = fileToDelete?.name || "File"; - - try { - // Delete the file using the Nhost storage SDK with the correct method name - await nhost.storage.deleteFile(fileId); - - // Show success message - setDeleteStatus({ - message: `${fileName} deleted successfully`, - isError: false, - }); - - // Update the local files list by removing the deleted file - setFiles(files.filter((file) => file.id !== fileId)); - - // Refresh the page to get updated file list from server - router.refresh(); - - // Clear the success message after 3 seconds - setTimeout(() => { - setDeleteStatus(null); - }, 3000); - } catch (err: unknown) { - // Show error message - setDeleteStatus({ - message: `Failed to delete ${fileName}: ${err instanceof Error ? err.message : "Unknown error"}`, - isError: true, - }); - console.error("Error deleting file:", err); - } finally { - setDeleting(null); - } - }; - - return ( - <> -
-

Upload a File

- -
- - -
- - {error &&
{error}
} - - {uploadResult && ( -
File uploaded successfully!
- )} - - -
- -
-

Your Files

- - {deleteStatus && ( -
- {deleteStatus.message} -
- )} - - {files.length === 0 ? ( -

No files uploaded yet.

- ) : ( -
- - - - - - - - - - - {files.map((file) => ( - - - - - - - ))} - -
NameTypeSizeActions
{file.name}{file.mimeType}{formatFileSize(file.size || 0)} -
- - -
-
-
- )} -
- - ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/upload/page.tsx b/examples/demos/nextjs-ssr-demo/src/app/upload/page.tsx deleted file mode 100644 index 38725e933..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/upload/page.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import type { FileMetadata } from "@nhost/nhost-js/storage"; -import { createNhostClient } from "../lib/nhost/server"; -import UploadClient from "./client"; - -interface GetFilesResponse { - files: FileMetadata[]; -} - -export default async function UploadPage() { - // Create the server client with async cookie access - const nhost = await createNhostClient(); - - // Fetch files on the server - let files: FileMetadata[] = []; - let error: string | null = null; - - try { - const response = await nhost.graphql.request({ - query: ` - query GetFiles { - files { - id - name - size - mimeType - bucketId - uploadedByUserId - } - } - `, - }); - - if (response.body.errors) { - throw new Error(response.body.errors[0]?.message); - } - - files = response.body.data?.files || []; - } catch (err) { - error = `Failed to load files: ${err instanceof Error ? err.message : "Unknown error"}`; - console.error("Error fetching files:", err); - } - - return ( -
-

File Upload

- - {/* Pass the server-fetched files to the client component */} - -
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/verify/error/page.tsx b/examples/demos/nextjs-ssr-demo/src/app/verify/error/page.tsx deleted file mode 100644 index 7e841626a..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/verify/error/page.tsx +++ /dev/null @@ -1,46 +0,0 @@ -interface ErrorPageProps { - searchParams: Promise<{ - message?: string; - [key: string]: string | undefined; - }>; -} - -export default async function VerificationError({ - searchParams, -}: ErrorPageProps) { - const params = await searchParams; - const errorMessage = params?.message || "Verification failed"; - - // Extract all URL parameters to display - const urlParams = { ...params }; - delete urlParams.message; // Remove message from parameters display since we're already showing it - - const hasUrlParams = Object.keys(urlParams).length > 0; - - return ( -
-
-

Verification Failed

-

{errorMessage}

- - {hasUrlParams && ( -
-

URL Parameters:

- {Object.entries(urlParams).map(([key, value]) => ( -
- {key}:{" "} - {value} -
- ))} -
- )} - - -
-
- ); -} diff --git a/examples/demos/nextjs-ssr-demo/src/app/verify/route.ts b/examples/demos/nextjs-ssr-demo/src/app/verify/route.ts deleted file mode 100644 index 90e3c0a46..000000000 --- a/examples/demos/nextjs-ssr-demo/src/app/verify/route.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import type { NextRequest } from "next/server"; -import { NextResponse } from "next/server"; -import { createNhostClient } from "../lib/nhost/server"; - -export async function GET(request: NextRequest) { - const refreshToken = request.nextUrl.searchParams.get("refreshToken"); - - if (!refreshToken) { - // Collect all query parameters - const params = new URLSearchParams(request.nextUrl.searchParams); - params.set("message", "No refresh token provided"); - - return NextResponse.redirect( - new URL(`/verify/error?${params.toString()}`, request.url), - ); - } - - try { - const nhost = await createNhostClient(); - - if (nhost.getUserSession()) { - // Collect all query parameters - const params = new URLSearchParams(request.nextUrl.searchParams); - params.set("message", "Already signed in"); - - return NextResponse.redirect( - new URL(`/verify/error?${params.toString()}`, request.url), - ); - } - - await nhost.auth.refreshToken({ refreshToken }); - - return NextResponse.redirect(new URL("/profile", request.url)); - } catch (err) { - const error = err as FetchError; - const errorMessage = `Failed to verify token: ${error.message}`; - - // Collect all query parameters - const params = new URLSearchParams(request.nextUrl.searchParams); - params.set("message", errorMessage); - - return NextResponse.redirect( - new URL(`/verify/error?${params.toString()}`, request.url), - ); - } -} diff --git a/examples/demos/nextjs-ssr-demo/src/middleware.ts b/examples/demos/nextjs-ssr-demo/src/middleware.ts deleted file mode 100644 index b37824acd..000000000 --- a/examples/demos/nextjs-ssr-demo/src/middleware.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { NextRequest } from "next/server"; -import { NextResponse } from "next/server"; -import { handleNhostMiddleware } from "./app/lib/nhost/server"; - -// Define public routes that don't require authentication -const publicRoutes = ["/signin", "/signup", "/verify"]; - -export async function middleware(request: NextRequest) { - // Create a response that we'll modify as needed - const response = NextResponse.next(); - - // Get the current path - const path = request.nextUrl.pathname; - - // Check if this is a public route or a public asset - const isPublicRoute = publicRoutes.some( - (route) => path === route || path.startsWith(`${route}/`), - ); - - // this is the only Nhost specific code in this middleware - // we call the Nhost middleware even on "public" routes - // to refresh the session if needed - const session = await handleNhostMiddleware(request, response); - - // If it's a public route, allow access without checking auth - if (isPublicRoute) { - return response; - } - - // If no session and not a public route, redirect to signin - if (!session) { - const signInUrl = new URL("/signin", request.url); - return NextResponse.redirect(signInUrl); - } - - // Session exists, allow access to protected route - return response; -} - -// Define which routes this middleware should run on -export const config = { - matcher: [ - /* - * Match all request paths except: - * - _next/static (static files) - * - _next/image (image optimization files) - * - favicon.ico (favicon file) - * - public files (public directory) - */ - "/((?!_next/static|_next/image|favicon.ico|public).*)", - ], -}; diff --git a/examples/demos/nextjs-ssr-demo/tsconfig.json b/examples/demos/nextjs-ssr-demo/tsconfig.json deleted file mode 100644 index 4e1ac9f43..000000000 --- a/examples/demos/nextjs-ssr-demo/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../../build/configs/tsconfig/frontend.json", - "compilerOptions": { - "jsx": "preserve", - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] -} diff --git a/examples/demos/package.json b/examples/demos/package.json deleted file mode 100644 index 5477dc4a2..000000000 --- a/examples/demos/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "demos", - "version": "1.0.0", - "license": "MIT", - "scripts": { - "build": "pnpm run --sequential --filter './**' build", - "test": "pnpm run --sequential --filter './**' test", - "generate": "pnpm run --sequential --filter './**' generate" - }, - "dependencies": { - "@nhost/nhost-js": "workspace:^" - } -} diff --git a/examples/demos/pnpm-lock.yaml b/examples/demos/pnpm-lock.yaml deleted file mode 100644 index 101832f3f..000000000 --- a/examples/demos/pnpm-lock.yaml +++ /dev/null @@ -1,13 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@nhost/nhost-js': - specifier: workspace:^ - version: link:../../packages/nhost-js diff --git a/examples/demos/project.nix b/examples/demos/project.nix deleted file mode 100644 index d534f8cfa..000000000 --- a/examples/demos/project.nix +++ /dev/null @@ -1,113 +0,0 @@ -{ self, pkgs, nix2containerPkgs, nix-filter, nixops-lib }: -let - name = "demos"; - version = "0.0.0-dev"; - submodule = "examples/${name}"; - - node_modules = nixops-lib.js.mkNodeModules { - name = "node-modules-${name}"; - version = "0.0.0-dev"; - - src = nix-filter.lib.filter { - root = ../..; - include = [ - ".npmrc " - "package.json" - "pnpm-workspace.yaml " - "pnpm-lock.yaml" - "${submodule}/package.json" - "${submodule}/pnpm-lock.yaml" - "${submodule}/ReactNativeDemo/package.json" - "${submodule}/ReactNativeDemo/pnpm-lock.yaml" - "${submodule}/express/package.json" - "${submodule}/express/pnpm-lock.yaml" - "${submodule}/nextjs-ssr-demo/package.json" - "${submodule}/nextjs-ssr-demo/pnpm-lock.yaml" - "${submodule}/react-demo/package.json" - "${submodule}/react-demo/pnpm-lock.yaml" - "${submodule}/sveltekit-demo/package.json" - "${submodule}/sveltekit-demo/pnpm-lock.yaml" - "${submodule}/vue-demo/package.json" - "${submodule}/vue-demo/pnpm-lock.yaml" - ]; - }; - - pnpmOpts = "--filter . --filter './${submodule}/**'"; - - preBuild = '' - mkdir packages - cp -r ${self.packages.${pkgs.system}.nhost-js} packages/nhost-js - ''; - }; - - src = nix-filter.lib.filter { - root = ../../.; - include = with nix-filter.lib; [ - isDirectory - ".gitignore" - ".npmrc" - "audit-ci.jsonc" - "biome.json" - "package.json" - "pnpm-workspace.yaml" - "pnpm-lock.yaml" - "turbo.json" - (inDirectory "./build") - (inDirectory "${submodule}") - ]; - }; - - checkDeps = with pkgs; [ nhost-cli biome ]; - - buildInputs = with pkgs; [ nodejs ]; - - nativeBuildInputs = with pkgs; [ pnpm cacert ]; -in -{ - devShell = nixops-lib.js.devShell { - inherit node_modules; - - buildInputs = [ - ] ++ checkDeps ++ buildInputs ++ nativeBuildInputs; - }; - - check = nixops-lib.js.check { - inherit src node_modules submodule buildInputs nativeBuildInputs checkDeps; - - preCheck = '' - rm -rf packages/nhost-js - cp -r ${self.packages.${pkgs.system}.nhost-js} packages/nhost-js - ''; - }; - - package = pkgs.stdenv.mkDerivation { - inherit name version src; - - nativeBuildInputs = with pkgs; [ pnpm cacert nodejs ]; - buildInputs = with pkgs; [ nodejs ]; - - buildPhase = '' - mkdir -p $TMPDIR/home - export HOME=$TMPDIR/home - - chmod +w -R . - - for absdir in $(pnpm list --recursive --depth=-1 --parseable); do - dir=$(realpath --relative-to="$PWD" "$absdir") - echo "➜ Copying node_modules for $dir" - cp -r ${node_modules}/$dir/node_modules $dir/node_modules - done - - rm -rf packages/nhost-js - cp -r ${self.packages.${pkgs.system}.nhost-js} packages/nhost-js - - cd ${submodule} - - pnpm build - ''; - - installPhase = '' - mkdir -p $out - ''; - }; -} diff --git a/examples/demos/react-demo/.gitignore b/examples/demos/react-demo/.gitignore deleted file mode 100644 index f52de6788..000000000 --- a/examples/demos/react-demo/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? -.vite diff --git a/examples/demos/react-demo/README.md b/examples/demos/react-demo/README.md deleted file mode 100644 index e5f45b148..000000000 --- a/examples/demos/react-demo/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# React Demo with Nhost SDK - -This demo application showcases how to use the Nhost SDK with React. - -## Features - -- Authentication (Sign up, Sign in, Sign out) -- Protected routes with centralized authentication checks -- Multi-factor Authentication (MFA) with TOTP -- File uploads and management -- User profile management -- Password change functionality - -## Project Structure - -- `/src/components` - Reusable UI components -- `/src/lib/nhost` - Nhost SDK configuration and hooks -- `/src/pages` - Application pages/routes -- `/src/utils` - Utility functions - -## Authentication Flow - -The application uses the `AuthProvider` from `/src/lib/nhost/AuthProvider.tsx` to manage authentication state and provide the Nhost client to all components. - -### Protected Routes - -The application uses a `ProtectedRoute` component (in `/src/components/ProtectedRoute.tsx`) as a layout route to handle authentication checks in a centralized way. This component: - -1. Checks if the user is authenticated -2. Shows a loading state when authentication status is being determined -3. Redirects to the sign-in page if not authenticated -4. Renders the child routes using React Router's `Outlet` component - -Usage in `App.tsx`: - -```tsx -}> - } /> - } /> - } /> - -``` - -This approach leverages React Router's layout routes feature to apply authentication protection to multiple routes without repeating code. It eliminates the need to add authentication checks in each protected page component. - -## Getting Started - -1. Clone the repository -2. Install dependencies: - ``` - pnpm install - ``` -3. Configure your Nhost environment variables in `.env` file -4. Start the development server: - ``` - pnpm dev - ``` - -## Environment Variables - -The application requires the following environment variables: - -- `VITE_NHOST_REGION` - Your Nhost region (e.g., "eu-central-1") -- `VITE_NHOST_SUBDOMAIN` - Your Nhost subdomain -- `VITE_ENV` - Environment (e.g., "development", "production") diff --git a/examples/demos/react-demo/index.html b/examples/demos/react-demo/index.html deleted file mode 100644 index 891a93804..000000000 --- a/examples/demos/react-demo/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + React - - -
- - - diff --git a/examples/demos/react-demo/package.json b/examples/demos/react-demo/package.json deleted file mode 100644 index 5699d60b1..000000000 --- a/examples/demos/react-demo/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "react-demo", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "generate": "echo 'Nothing to do'", - "test": "pnpm test:typecheck && pnpm test:lint", - "test:typecheck": "tsc --noEmit", - "test:lint": "biome check", - "format": "biome format --write", - "preview": "vite preview" - }, - "dependencies": { - "@nhost/nhost-js": "workspace:*", - "@simplewebauthn/browser": "^13.1.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-router-dom": "^7.6.0" - }, - "devDependencies": { - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.2", - "@vitejs/plugin-react": "^4.4.1" - } -} diff --git a/examples/demos/react-demo/pnpm-lock.yaml b/examples/demos/react-demo/pnpm-lock.yaml deleted file mode 100644 index 0c72a5e8d..000000000 --- a/examples/demos/react-demo/pnpm-lock.yaml +++ /dev/null @@ -1,1119 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@nhost/nhost-js': - specifier: workspace:* - version: link:../../../packages/nhost-js - '@simplewebauthn/browser': - specifier: ^13.1.0 - version: 13.1.2 - react: - specifier: ^19.1.0 - version: 19.1.1 - react-dom: - specifier: ^19.1.0 - version: 19.1.1(react@19.1.1) - react-router-dom: - specifier: ^7.6.0 - version: 7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - devDependencies: - '@types/react': - specifier: ^19.1.2 - version: 19.1.12 - '@types/react-dom': - specifier: ^19.1.2 - version: 19.1.9(@types/react@19.1.12) - '@vitejs/plugin-react': - specifier: ^4.4.1 - version: 4.7.0(vite@7.1.11) - -packages: - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.28.0': - resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.28.4': - resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.4': - resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} - engines: {node: '>=6.9.0'} - - '@esbuild/aix-ppc64@0.25.9': - resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.9': - resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.9': - resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.9': - resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.9': - resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.9': - resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.9': - resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.9': - resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.9': - resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.9': - resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.9': - resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.9': - resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.9': - resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.9': - resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.9': - resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.9': - resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.9': - resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.9': - resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.9': - resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.9': - resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.9': - resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.9': - resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.9': - resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.9': - resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.9': - resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.9': - resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.30': - resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} - - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - - '@rollup/rollup-android-arm-eabi@4.50.0': - resolution: {integrity: sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.50.0': - resolution: {integrity: sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.50.0': - resolution: {integrity: sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.50.0': - resolution: {integrity: sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.50.0': - resolution: {integrity: sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.50.0': - resolution: {integrity: sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.50.0': - resolution: {integrity: sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.50.0': - resolution: {integrity: sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.50.0': - resolution: {integrity: sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.50.0': - resolution: {integrity: sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loongarch64-gnu@4.50.0': - resolution: {integrity: sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.50.0': - resolution: {integrity: sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.50.0': - resolution: {integrity: sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.50.0': - resolution: {integrity: sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.50.0': - resolution: {integrity: sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.50.0': - resolution: {integrity: sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.50.0': - resolution: {integrity: sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openharmony-arm64@4.50.0': - resolution: {integrity: sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.50.0': - resolution: {integrity: sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.50.0': - resolution: {integrity: sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.50.0': - resolution: {integrity: sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==} - cpu: [x64] - os: [win32] - - '@simplewebauthn/browser@13.1.2': - resolution: {integrity: sha512-aZnW0KawAM83fSBUgglP5WofbrLbLyr7CoPqYr66Eppm7zO86YX6rrCjRB3hQKPrL7ATvY4FVXlykZ6w6FwYYw==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/react-dom@19.1.9': - resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==} - peerDependencies: - '@types/react': ^19.0.0 - - '@types/react@19.1.12': - resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==} - - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - browserslist@4.25.4: - resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - caniuse-lite@1.0.30001739: - resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie@1.0.2: - resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} - engines: {node: '>=18'} - - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - electron-to-chromium@1.5.214: - resolution: {integrity: sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==} - - esbuild@0.25.9: - resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - react-dom@19.1.1: - resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} - peerDependencies: - react: ^19.1.1 - - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react-router-dom@7.8.2: - resolution: {integrity: sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - - react-router@7.8.2: - resolution: {integrity: sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - peerDependenciesMeta: - react-dom: - optional: true - - react@19.1.1: - resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} - engines: {node: '>=0.10.0'} - - rollup@4.50.0: - resolution: {integrity: sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - set-cookie-parser@2.7.1: - resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - vite@7.1.11: - resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - -snapshots: - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.0': {} - - '@babel/core@7.28.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.1 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.3': - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.4 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.27.1': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.4': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - - '@babel/parser@7.28.4': - dependencies: - '@babel/types': 7.28.4 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/template@7.27.2': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - - '@babel/traverse@7.28.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.28.4': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - - '@esbuild/aix-ppc64@0.25.9': - optional: true - - '@esbuild/android-arm64@0.25.9': - optional: true - - '@esbuild/android-arm@0.25.9': - optional: true - - '@esbuild/android-x64@0.25.9': - optional: true - - '@esbuild/darwin-arm64@0.25.9': - optional: true - - '@esbuild/darwin-x64@0.25.9': - optional: true - - '@esbuild/freebsd-arm64@0.25.9': - optional: true - - '@esbuild/freebsd-x64@0.25.9': - optional: true - - '@esbuild/linux-arm64@0.25.9': - optional: true - - '@esbuild/linux-arm@0.25.9': - optional: true - - '@esbuild/linux-ia32@0.25.9': - optional: true - - '@esbuild/linux-loong64@0.25.9': - optional: true - - '@esbuild/linux-mips64el@0.25.9': - optional: true - - '@esbuild/linux-ppc64@0.25.9': - optional: true - - '@esbuild/linux-riscv64@0.25.9': - optional: true - - '@esbuild/linux-s390x@0.25.9': - optional: true - - '@esbuild/linux-x64@0.25.9': - optional: true - - '@esbuild/netbsd-arm64@0.25.9': - optional: true - - '@esbuild/netbsd-x64@0.25.9': - optional: true - - '@esbuild/openbsd-arm64@0.25.9': - optional: true - - '@esbuild/openbsd-x64@0.25.9': - optional: true - - '@esbuild/openharmony-arm64@0.25.9': - optional: true - - '@esbuild/sunos-x64@0.25.9': - optional: true - - '@esbuild/win32-arm64@0.25.9': - optional: true - - '@esbuild/win32-ia32@0.25.9': - optional: true - - '@esbuild/win32-x64@0.25.9': - optional: true - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.30 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.30': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@rolldown/pluginutils@1.0.0-beta.27': {} - - '@rollup/rollup-android-arm-eabi@4.50.0': - optional: true - - '@rollup/rollup-android-arm64@4.50.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.50.0': - optional: true - - '@rollup/rollup-darwin-x64@4.50.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.50.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.50.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.50.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.50.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.50.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.50.0': - optional: true - - '@rollup/rollup-linux-loongarch64-gnu@4.50.0': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.50.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.50.0': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.50.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.50.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.50.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.50.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.50.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.50.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.50.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.50.0': - optional: true - - '@simplewebauthn/browser@13.1.2': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.4 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.28.4 - - '@types/estree@1.0.8': {} - - '@types/react-dom@19.1.9(@types/react@19.1.12)': - dependencies: - '@types/react': 19.1.12 - - '@types/react@19.1.12': - dependencies: - csstype: 3.1.3 - - '@vitejs/plugin-react@4.7.0(vite@7.1.11)': - dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.1.11 - transitivePeerDependencies: - - supports-color - - browserslist@4.25.4: - dependencies: - caniuse-lite: 1.0.30001739 - electron-to-chromium: 1.5.214 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.25.4) - - caniuse-lite@1.0.30001739: {} - - convert-source-map@2.0.0: {} - - cookie@1.0.2: {} - - csstype@3.1.3: {} - - debug@4.4.1: - dependencies: - ms: 2.1.3 - - electron-to-chromium@1.5.214: {} - - esbuild@0.25.9: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.9 - '@esbuild/android-arm': 0.25.9 - '@esbuild/android-arm64': 0.25.9 - '@esbuild/android-x64': 0.25.9 - '@esbuild/darwin-arm64': 0.25.9 - '@esbuild/darwin-x64': 0.25.9 - '@esbuild/freebsd-arm64': 0.25.9 - '@esbuild/freebsd-x64': 0.25.9 - '@esbuild/linux-arm': 0.25.9 - '@esbuild/linux-arm64': 0.25.9 - '@esbuild/linux-ia32': 0.25.9 - '@esbuild/linux-loong64': 0.25.9 - '@esbuild/linux-mips64el': 0.25.9 - '@esbuild/linux-ppc64': 0.25.9 - '@esbuild/linux-riscv64': 0.25.9 - '@esbuild/linux-s390x': 0.25.9 - '@esbuild/linux-x64': 0.25.9 - '@esbuild/netbsd-arm64': 0.25.9 - '@esbuild/netbsd-x64': 0.25.9 - '@esbuild/openbsd-arm64': 0.25.9 - '@esbuild/openbsd-x64': 0.25.9 - '@esbuild/openharmony-arm64': 0.25.9 - '@esbuild/sunos-x64': 0.25.9 - '@esbuild/win32-arm64': 0.25.9 - '@esbuild/win32-ia32': 0.25.9 - '@esbuild/win32-x64': 0.25.9 - - escalade@3.2.0: {} - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - fsevents@2.3.3: - optional: true - - gensync@1.0.0-beta.2: {} - - js-tokens@4.0.0: {} - - jsesc@3.1.0: {} - - json5@2.2.3: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - ms@2.1.3: {} - - nanoid@3.3.11: {} - - node-releases@2.0.19: {} - - picocolors@1.1.1: {} - - picomatch@4.0.3: {} - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - react-dom@19.1.1(react@19.1.1): - dependencies: - react: 19.1.1 - scheduler: 0.26.0 - - react-refresh@0.17.0: {} - - react-router-dom@7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): - dependencies: - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - react-router: 7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - - react-router@7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): - dependencies: - cookie: 1.0.2 - react: 19.1.1 - set-cookie-parser: 2.7.1 - optionalDependencies: - react-dom: 19.1.1(react@19.1.1) - - react@19.1.1: {} - - rollup@4.50.0: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.50.0 - '@rollup/rollup-android-arm64': 4.50.0 - '@rollup/rollup-darwin-arm64': 4.50.0 - '@rollup/rollup-darwin-x64': 4.50.0 - '@rollup/rollup-freebsd-arm64': 4.50.0 - '@rollup/rollup-freebsd-x64': 4.50.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.50.0 - '@rollup/rollup-linux-arm-musleabihf': 4.50.0 - '@rollup/rollup-linux-arm64-gnu': 4.50.0 - '@rollup/rollup-linux-arm64-musl': 4.50.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.50.0 - '@rollup/rollup-linux-ppc64-gnu': 4.50.0 - '@rollup/rollup-linux-riscv64-gnu': 4.50.0 - '@rollup/rollup-linux-riscv64-musl': 4.50.0 - '@rollup/rollup-linux-s390x-gnu': 4.50.0 - '@rollup/rollup-linux-x64-gnu': 4.50.0 - '@rollup/rollup-linux-x64-musl': 4.50.0 - '@rollup/rollup-openharmony-arm64': 4.50.0 - '@rollup/rollup-win32-arm64-msvc': 4.50.0 - '@rollup/rollup-win32-ia32-msvc': 4.50.0 - '@rollup/rollup-win32-x64-msvc': 4.50.0 - fsevents: 2.3.3 - - scheduler@0.26.0: {} - - semver@6.3.1: {} - - set-cookie-parser@2.7.1: {} - - source-map-js@1.2.1: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - update-browserslist-db@1.1.3(browserslist@4.25.4): - dependencies: - browserslist: 4.25.4 - escalade: 3.2.0 - picocolors: 1.1.1 - - vite@7.1.11: - dependencies: - esbuild: 0.25.9 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.50.0 - tinyglobby: 0.2.15 - optionalDependencies: - fsevents: 2.3.3 - - yallist@3.1.1: {} diff --git a/examples/demos/react-demo/public/vite.svg b/examples/demos/react-demo/public/vite.svg deleted file mode 100644 index e7b8dfb1b..000000000 --- a/examples/demos/react-demo/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/demos/react-demo/src/App.css b/examples/demos/react-demo/src/App.css deleted file mode 100644 index b9d355df2..000000000 --- a/examples/demos/react-demo/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/examples/demos/react-demo/src/App.tsx b/examples/demos/react-demo/src/App.tsx deleted file mode 100644 index 1b3516af7..000000000 --- a/examples/demos/react-demo/src/App.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { type JSX, lazy, Suspense } from "react"; -import { - createBrowserRouter, - createRoutesFromElements, - Navigate, - Outlet, - Route, - RouterProvider, -} from "react-router-dom"; -import Navigation from "./components/Navigation"; -import ProtectedRoute from "./components/ProtectedRoute"; -import { AuthProvider } from "./lib/nhost/AuthProvider"; -import Home from "./pages/Home"; -import Profile from "./pages/Profile"; -import SignIn from "./pages/SignIn"; -import SignUp from "./pages/SignUp"; -import Todos from "./pages/Todos"; -import Upload from "./pages/Upload"; -import Verify from "./pages/Verify"; - -const MfaVerification = lazy(() => import("./pages/signin/mfa")); - -// Root layout component to wrap all routes -const RootLayout = (): JSX.Element => { - return ( -
- -
- -
-
-

- © {new Date().getFullYear()} Nhost Demo -

-
-
- ); -}; - -// Create router with routes -const router = createBrowserRouter( - createRoutesFromElements( - }> - } /> - } /> - Loading...} - > - - - } - /> - } /> - } /> - }> - } /> - } /> - } /> - - } /> - , - ), -); - -const App = (): JSX.Element => { - return ( - - - - ); -}; - -export default App; diff --git a/examples/demos/react-demo/src/assets/react.svg b/examples/demos/react-demo/src/assets/react.svg deleted file mode 100644 index 6c87de9bb..000000000 --- a/examples/demos/react-demo/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/demos/react-demo/src/components/ChangePassword.tsx b/examples/demos/react-demo/src/components/ChangePassword.tsx deleted file mode 100644 index 22fd424f9..000000000 --- a/examples/demos/react-demo/src/components/ChangePassword.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { type JSX, useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -export default function ChangePassword(): JSX.Element { - const [newPassword, setNewPassword] = useState(""); - const [confirmPassword, setConfirmPassword] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(""); - const [success, setSuccess] = useState(false); - const { nhost } = useAuth(); - const newPasswordId = useId(); - const confirmPasswordId = useId(); - - const handleSubmit = async ( - e: React.FormEvent, - ): Promise => { - e.preventDefault(); - - // Reset states - setError(""); - setSuccess(false); - - // Validate passwords - if (newPassword.length < 3) { - setError("Password must be at least 3 characters long"); - return; - } - - if (newPassword !== confirmPassword) { - setError("Passwords do not match"); - return; - } - - setIsLoading(true); - - try { - // Use the changeUserPassword method from the SDK - await nhost.auth.changeUserPassword({ - newPassword, - }); - setSuccess(true); - setNewPassword(""); - setConfirmPassword(""); - } catch (err) { - const error = err as FetchError; - setError( - `An error occurred while changing the password: ${error.message}`, - ); - } finally { - setIsLoading(false); - } - }; - - return ( -
-

Change Password

- - {success && ( -
- Password changed successfully! -
- )} - - {error &&
{error}
} - -
-
- - setNewPassword(e.target.value)} - className="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500" - required - minLength={3} - disabled={isLoading} - /> -
- -
- - setConfirmPassword(e.target.value)} - className="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500" - required - disabled={isLoading} - /> -
- - -
-
- ); -} diff --git a/examples/demos/react-demo/src/components/MFASettings.tsx b/examples/demos/react-demo/src/components/MFASettings.tsx deleted file mode 100644 index 8ec83cff4..000000000 --- a/examples/demos/react-demo/src/components/MFASettings.tsx +++ /dev/null @@ -1,288 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { type JSX, useEffect, useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface MFASettingsProps { - initialMfaEnabled: boolean; -} - -export default function MFASettings({ - initialMfaEnabled, -}: MFASettingsProps): JSX.Element { - const [isMfaEnabled, setIsMfaEnabled] = useState(initialMfaEnabled); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [success, setSuccess] = useState(null); - const { nhost } = useAuth(); - const verificationCodeId = useId(); - const disableVerificationCodeId = useId(); - - // Update internal state when prop changes - useEffect(() => { - if (initialMfaEnabled !== isMfaEnabled) { - setIsMfaEnabled(initialMfaEnabled); - } - }, [initialMfaEnabled, isMfaEnabled]); - - // MFA setup states - const [isSettingUpMfa, setIsSettingUpMfa] = useState(false); - const [totpSecret, setTotpSecret] = useState(""); - const [qrCodeUrl, setQrCodeUrl] = useState(""); - const [verificationCode, setVerificationCode] = useState(""); - - // Disabling MFA states - const [isDisablingMfa, setIsDisablingMfa] = useState(false); - const [disableVerificationCode, setDisableVerificationCode] = - useState(""); - - // Begin MFA setup process - const handleEnableMfa = async (): Promise => { - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Generate TOTP secret - const response = await nhost.auth.changeUserMfa(); - setTotpSecret(response.body.totpSecret); - setQrCodeUrl(response.body.imageUrl); - setIsSettingUpMfa(true); - } catch (err) { - const error = err as FetchError; - setError(`An error occurred while enabling MFA: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - // Verify TOTP and enable MFA - const handleVerifyTotp = async (): Promise => { - if (!verificationCode) { - setError("Please enter the verification code"); - return; - } - - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Verify and activate MFA - await nhost.auth.verifyChangeUserMfa({ - activeMfaType: "totp", - code: verificationCode, - }); - - setIsMfaEnabled(true); - setIsSettingUpMfa(false); - setSuccess("MFA has been successfully enabled."); - } catch (err) { - const error = err as FetchError; - setError(`An error occurred while verifying the code: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - // Show disable MFA confirmation - const handleShowDisableMfa = (): void => { - setIsDisablingMfa(true); - setError(null); - setSuccess(null); - }; - - // Disable MFA - const handleDisableMfa = async (): Promise => { - if (!disableVerificationCode) { - setError("Please enter your verification code to confirm"); - return; - } - - setIsLoading(true); - setError(null); - setSuccess(null); - - try { - // Disable MFA by setting activeMfaType to empty string - await nhost.auth.verifyChangeUserMfa({ - activeMfaType: "", - code: disableVerificationCode, - }); - - setIsMfaEnabled(false); - setIsDisablingMfa(false); - setDisableVerificationCode(""); - setSuccess("MFA has been successfully disabled."); - } catch (err) { - const error = err as FetchError; - setError(`An error occurred while disabling MFA: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - // Cancel MFA setup - const handleCancelMfaSetup = (): void => { - setIsSettingUpMfa(false); - setTotpSecret(""); - setQrCodeUrl(""); - setVerificationCode(""); - }; - - // Cancel MFA disable - const handleCancelMfaDisable = (): void => { - setIsDisablingMfa(false); - setDisableVerificationCode(""); - setError(null); - }; - - return ( -
-

Multi-Factor Authentication

- - {error &&
{error}
} - - {success &&
{success}
} - - {isSettingUpMfa ? ( -
-

- Scan this QR code with your authenticator app (e.g., Google - Authenticator, Authy): -

- - {qrCodeUrl && ( -
-
- TOTP QR Code -
-
- )} - -

Or manually enter this secret key:

-
- {totpSecret} -
- -
- - setVerificationCode(e.target.value)} - placeholder="Enter 6-digit code" - maxLength={6} - required - /> -
- -
- - - -
-
- ) : isDisablingMfa ? ( -
-

- To disable Multi-Factor Authentication, please enter the current - verification code from your authenticator app. -

- -
- - setDisableVerificationCode(e.target.value)} - placeholder="Enter 6-digit code" - maxLength={6} - required - /> -
- -
- - - -
-
- ) : ( -
-

- Multi-Factor Authentication adds an extra layer of security to your - account by requiring a verification code from your authenticator app - when signing in. -

- -
- Status: - - {isMfaEnabled ? "Enabled" : "Disabled"} - -
- - {isMfaEnabled ? ( - - ) : ( - - )} -
- )} -
- ); -} diff --git a/examples/demos/react-demo/src/components/MagicLinkForm.tsx b/examples/demos/react-demo/src/components/MagicLinkForm.tsx deleted file mode 100644 index 5c367e6c0..000000000 --- a/examples/demos/react-demo/src/components/MagicLinkForm.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import React, { type JSX, useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface MagicLinkFormProps { - buttonLabel?: string; -} - -export default function MagicLinkForm({ - buttonLabel = "Send Magic Link", -}: MagicLinkFormProps): JSX.Element { - const [email, setEmail] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [success, setSuccess] = useState(false); - const [error, setError] = useState(null); - const { nhost } = useAuth(); - const emailId = useId(); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setIsLoading(true); - setError(null); - - try { - await nhost.auth.signInPasswordlessEmail({ - email, - options: { - redirectTo: `${window.location.origin}/verify`, - }, - }); - - setSuccess(true); - } catch (err) { - const error = err as FetchError; - setError( - `An error occurred while sending the magic link: ${error.message}`, - ); - } finally { - setIsLoading(false); - } - }; - - if (success) { - return ( -
-

Magic link sent! Check your email to sign in.

- -
- ); - } - - return ( -
-
- - setEmail(e.target.value)} - required - /> -
- - {error &&
{error}
} - - -
- ); -} diff --git a/examples/demos/react-demo/src/components/Navigation.tsx b/examples/demos/react-demo/src/components/Navigation.tsx deleted file mode 100644 index 5494ded70..000000000 --- a/examples/demos/react-demo/src/components/Navigation.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import type { JSX } from "react"; -import { Link, useLocation } from "react-router-dom"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -export default function Navigation(): JSX.Element { - const { isAuthenticated, nhost, session } = useAuth(); - const location = useLocation(); - - // Helper function to determine if a link is active - const isActive = (path: string): string => { - return location.pathname === path ? "active" : ""; - }; - - return ( - - ); -} diff --git a/examples/demos/react-demo/src/components/ProtectedRoute.tsx b/examples/demos/react-demo/src/components/ProtectedRoute.tsx deleted file mode 100644 index 1b99efe2a..000000000 --- a/examples/demos/react-demo/src/components/ProtectedRoute.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Navigate, Outlet } from "react-router-dom"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface ProtectedRouteProps { - redirectTo?: string; -} - -export default function ProtectedRoute({ - redirectTo = "/signin", -}: ProtectedRouteProps) { - const { isAuthenticated, isLoading } = useAuth(); - - if (isLoading) { - return ( -
-

Loading...

-
- ); - } - - if (!isAuthenticated) { - return ; - } - - return ; -} diff --git a/examples/demos/react-demo/src/components/SecurityKeys.tsx b/examples/demos/react-demo/src/components/SecurityKeys.tsx deleted file mode 100644 index 9a704617c..000000000 --- a/examples/demos/react-demo/src/components/SecurityKeys.tsx +++ /dev/null @@ -1,404 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError, FetchResponse } from "@nhost/nhost-js/fetch"; -import { startRegistration } from "@simplewebauthn/browser"; -import { useCallback, useEffect, useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; -import { isWebAuthnSupported } from "../lib/utils"; - -/** - * Represents a WebAuthn security key stored for a user - * - id: Database ID for the key - * - credentialId: WebAuthn credential identifier - * - nickname: User-provided friendly name for the key - */ -interface SecurityKey { - id: string; - credentialId: string; - nickname: string | null; -} - -/** - * GraphQL response format for security keys query - */ -interface SecurityKeysResponse { - data?: { - authUserSecurityKeys: SecurityKey[]; - }; -} - -export default function SecurityKeys() { - const { nhost, isAuthenticated } = useAuth(); - const [securityKeys, setSecurityKeys] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [isRegistering, setIsRegistering] = useState(false); - const [isDeleting, setIsDeleting] = useState(false); - const [deletingKeyId, setDeletingKeyId] = useState(null); - const [keyName, setKeyName] = useState(""); - const [success, setSuccess] = useState(null); - const [errorMessage, setErrorMessage] = useState(null); - const [showAddForm, setShowAddForm] = useState(false); - const [isWebAuthnAvailable, setIsWebAuthnAvailable] = useState(true); - const keyNameId = useId(); - - /** - * Fetches all registered WebAuthn security keys for the current user - * These are the public keys stored on the server that correspond to - * private keys stored securely on the user's devices/authenticators - */ - const fetchSecurityKeys = useCallback(async (): Promise => { - setIsLoading(true); - setErrorMessage(null); - - try { - // Query the database for all security keys registered to this user - const response: FetchResponse = - await nhost.graphql.request({ - query: ` - query GetUserSecurityKeys { - authUserSecurityKeys { - id - credentialId - nickname - } - } - `, - }); - - const userData = response.body?.data; - const keys = userData?.authUserSecurityKeys || []; - setSecurityKeys(keys); - } catch (err) { - const error = err as FetchError; - setErrorMessage(`Failed to load security keys: ${error.message}`); - } finally { - setIsLoading(false); - } - }, [nhost.graphql]); - - const deleteSecurityKey = async (keyId: string): Promise => { - if (isDeleting) return; - - setIsDeleting(true); - setDeletingKeyId(keyId); - setSuccess(null); - setErrorMessage(null); - - try { - // Send request to server to delete the security key - // This removes the stored public key from the server database - // so it can no longer be used for authentication - const response = await nhost.graphql.request({ - query: ` - mutation DeleteSecurityKey($keyId: uuid!) { - deleteAuthUserSecurityKey(id: $keyId) { - id - } - } - `, - variables: { - keyId, - }, - }); - - if (response.body?.errors) { - throw new Error(response.body.errors[0]?.message || "Unknown error"); - } - - // Update the UI by removing the key from local state - setSecurityKeys(securityKeys.filter((key) => key.id !== keyId)); - setSuccess( - "Security key deleted successfully! Remember to also remove it from your authenticator app, password manager, or device credential manager to avoid future authentication issues.", - ); - - // Hide success message after 5 seconds (increased to give users time to read the reminder) - setTimeout(() => { - setSuccess(null); - }, 5000); - } catch (err) { - const error = err as Error; - setErrorMessage(`Failed to delete security key: ${error.message}`); - } finally { - setIsDeleting(false); - setDeletingKeyId(null); - } - }; - - useEffect(() => { - // Check if the current browser supports WebAuthn - // This tests for the presence of the WebAuthn API (PublicKeyCredential and credentials) - setIsWebAuthnAvailable(isWebAuthnSupported()); - - // Load the user's security keys when authenticated - if (isAuthenticated) { - fetchSecurityKeys(); - } - }, [isAuthenticated, fetchSecurityKeys]); - - if (isLoading) { - return ( -
-

Security Keys

-

Loading security keys...

-
- ); - } - - const registerNewSecurityKey = async (e: React.FormEvent) => { - e.preventDefault(); - - // Check if browser supports WebAuthn - if (!isWebAuthnAvailable) { - setErrorMessage( - "WebAuthn is not supported by your browser. Please use a modern browser that supports WebAuthn.", - ); - return; - } - - // Validate key name exists - if (!keyName.trim()) { - setErrorMessage("Please provide a name for your security key"); - return; - } - - setIsRegistering(true); - setErrorMessage(null); - setSuccess(null); - - try { - // Step 1: Request challenge from server - // The server generates a random challenge to ensure the registration - // is happening in real-time and creates a new credential ID - const initResponse = await nhost.auth.addSecurityKey(); - - // Step 2: Browser prompts user for security key or biometric verification - // The browser creates a new credential pair (public/private) and stores - // the private key securely on the device - const credential = await startRegistration({ - optionsJSON: initResponse.body, - }); - - if (!credential) { - setErrorMessage("No credential was selected. Please try again."); - return; - } - - // Step 3: Send credential public key back to server for verification - // The server verifies the attestation and stores the public key - // associated with the user's account for future authentication - await nhost.auth.verifyAddSecurityKey({ - credential, - nickname: keyName.trim(), - }); - - // Step 4: Registration successful - update UI - setSuccess("Security key registered successfully!"); - setKeyName(""); - setShowAddForm(false); - - // Refresh the security keys list - fetchSecurityKeys(); - } catch (err) { - const error = err as Error; - setErrorMessage(`Failed to register security key: ${error.message}`); - } finally { - setIsRegistering(false); - } - }; - - const toggleAddForm = () => { - setShowAddForm(!showAddForm); - setErrorMessage(null); - setSuccess(null); - setKeyName(""); - }; - - return ( -
-

Security Keys

- - {errorMessage && ( -
{errorMessage}
- )} - - {success &&
{success}
} - - {!isWebAuthnAvailable && ( -
-

- WebAuthn not supported! Your browser or device - doesn't support WebAuthn authentication. Please use a modern - browser (Chrome, Firefox, Safari, Edge) that supports WebAuthn. -

-

- Note: Even if your browser supports WebAuthn, you may need a - compatible authenticator like a fingerprint reader, facial - recognition, or a security key (e.g., YubiKey). -

-
- )} - - {showAddForm ? ( -
-

- Enter a name for your security key and follow the prompts from your - browser to register it. -

-

- Note: You'll need a security key (like YubiKey) or a device - with biometric authentication (like Touch ID, Face ID, or Windows - Hello). If registration fails, make sure your device has the - required capabilities. -

-

- This works the same way as when you registered during sign up. -

- -
-
- - setKeyName(e.target.value)} - placeholder="e.g., My YubiKey, Touch ID, Windows Hello" - disabled={isRegistering} - required - /> -
-
- - -
-
-
- ) : ( -
-

- Security Keys (WebAuthn) provide a secure passwordless - authentication option using hardware security keys, fingerprints, or - facial recognition. -

- - {/* List of existing security keys */} - {securityKeys.length === 0 ? ( -

No security keys registered.

- ) : ( -
-
    - {securityKeys.map((key) => ( -
  • -
    - - {key.nickname || "Unnamed key"} - - - ID: {key.credentialId.slice(0, 8)}... - -
    - -
  • - ))} -
-
- )} - - -
- )} -
- ); -} diff --git a/examples/demos/react-demo/src/components/TabForm.tsx b/examples/demos/react-demo/src/components/TabForm.tsx deleted file mode 100644 index 6cfe620ef..000000000 --- a/examples/demos/react-demo/src/components/TabForm.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { type JSX, type ReactNode, useState } from "react"; - -interface TabFormProps { - passwordTabContent: ReactNode; - magicTabContent: ReactNode; - socialTabContent?: ReactNode; - webauthnTabContent?: ReactNode; -} - -export default function TabForm({ - passwordTabContent, - magicTabContent, - socialTabContent, - webauthnTabContent, -}: TabFormProps): JSX.Element { - const [activeTab, setActiveTab] = useState< - "password" | "magic" | "social" | "webauthn" - >("password"); - - return ( -
-
- - - {socialTabContent && ( - - )} - {webauthnTabContent && ( - - )} -
- -
- {activeTab === "password" - ? passwordTabContent - : activeTab === "magic" - ? magicTabContent - : activeTab === "social" - ? socialTabContent - : webauthnTabContent} -
-
- ); -} diff --git a/examples/demos/react-demo/src/components/WebAuthnSignInForm.tsx b/examples/demos/react-demo/src/components/WebAuthnSignInForm.tsx deleted file mode 100644 index 269b7b20f..000000000 --- a/examples/demos/react-demo/src/components/WebAuthnSignInForm.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { startAuthentication } from "@simplewebauthn/browser"; -import { type JSX, useState } from "react"; -import { useNavigate } from "react-router-dom"; -import { useAuth } from "../lib/nhost/AuthProvider"; -import { isWebAuthnSupported } from "../lib/utils"; - -/** - * WebAuthnSignInForm provides a passwordless authentication flow using WebAuthn (FIDO2) protocol. - * This enables users to authenticate using biometrics, hardware security keys, or platform authenticators - * instead of traditional passwords. - */ -export default function WebAuthnSignInForm(): JSX.Element { - const { nhost } = useAuth(); - const navigate = useNavigate(); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - - /** - * Handles the WebAuthn authentication flow: - * 1. Request a challenge from the server - * 2. Have the browser/authenticator sign the challenge with the private key - * 3. Verify the signature on the server and establish a session - */ - const startWebAuthnSignIn = async ( - e: React.FormEvent, - ): Promise => { - e.preventDefault(); - setIsLoading(true); - setError(null); - - try { - // First check if WebAuthn is supported by this browser - if (!isWebAuthnSupported()) { - setError("WebAuthn is not supported by your browser."); - setIsLoading(false); - return; - } - - // Step 1: Request a challenge from the server for credential discovery - // The server creates a random challenge and sends allowed credential information - // This prevents replay attacks by ensuring each authentication attempt is unique - const response = await nhost.auth.signInWebauthn(); - - try { - // Step 2: Browser prompts user for their security key or biometric verification - // The navigator.credentials.get() API activates the authenticator (fingerprint reader, - // security key, etc.) and asks the user to verify their identity - // The authenticator then signs the challenge with the private key - const credential = await startAuthentication({ - optionsJSON: response.body, - }); - - if (!credential) { - setError("No credential was selected."); - setIsLoading(false); - return; - } - - // Step 3: Send the signed challenge to the server for verification - // The server validates the signature using the stored public key - // If valid, the server creates an authenticated session - const verifyResponse = await nhost.auth.verifySignInWebauthn({ - credential, - }); - - // Step 4: Handle authentication result - if (verifyResponse.body?.session) { - // Authentication successful, redirect to profile page - navigate("/profile"); - } else { - setError("Authentication failed"); - } - } catch (credError) { - setError( - `WebAuthn authentication failed: ${(credError as Error).message || "Unknown error"}`, - ); - } - } catch (err) { - const error = err as FetchError; - setError(`An error occurred during WebAuthn sign in: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - return ( -
- {error &&
{error}
} - - - -
-

- You'll be prompted to use your device's security key (like - TouchID, FaceID, Windows Hello, or a USB security key) -

-

- Your browser will show available security keys that you've - previously registered. -

-
-
- ); -} diff --git a/examples/demos/react-demo/src/components/WebAuthnSignUpForm.tsx b/examples/demos/react-demo/src/components/WebAuthnSignUpForm.tsx deleted file mode 100644 index 2fbc557b0..000000000 --- a/examples/demos/react-demo/src/components/WebAuthnSignUpForm.tsx +++ /dev/null @@ -1,215 +0,0 @@ -import type { - ErrorResponse, - PublicKeyCredentialCreationOptions, -} from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { startRegistration } from "@simplewebauthn/browser"; -import { type JSX, useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; -import { isWebAuthnSupported } from "../lib/utils"; - -/** - * WebAuthn Registration (Sign Up) Flow - * - * This component handles new user registration using WebAuthn/FIDO2 standards. - * Instead of creating a password, users register using biometrics or security keys, - * providing a more secure and phishing-resistant authentication method. - */ - -/** - * Props for the WebAuthn signup form - * @param email - User's email address - * @param setEmail - Function to update email state - * @param displayName - User's display name - * @param setDisplayName - Function to update display name state - * @param redirectTo - Optional URL to redirect after successful registration - */ -interface WebAuthnFormProps { - email: string; - setEmail: (email: string) => void; - displayName: string; - setDisplayName: (name: string) => void; - redirectTo?: string; -} - -export default function WebAuthnSignUpForm({ - email, - setEmail, - displayName, - setDisplayName, - redirectTo, -}: WebAuthnFormProps): JSX.Element { - const { nhost } = useAuth(); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [keyNickname, setKeyNickname] = useState(""); - const [challengeData, setChallengeData] = - useState(null); - const displayNameId = useId(); - const emailId = useId(); - const keyNicknameId = useId(); - - /** - * Handles the WebAuthn registration flow (sign up with security key/biometrics) - * - * The WebAuthn registration flow consists of: - * 1. Server generates a challenge and user verification requirements - * 2. Browser activates the authenticator and creates new credential key pair - * 3. The private key remains securely on the user's device - * 4. The public key and attestation are sent to the server for verification - * 5. Server stores the public key for future authentication attempts - */ - const startWebAuthnRegistration = async ( - e: React.FormEvent, - ): Promise => { - e.preventDefault(); - setIsLoading(true); - setError(null); - - // Validate required fields - if (!email) { - setError("Email is required"); - setIsLoading(false); - return; - } - - // Check browser compatibility before proceeding - if (!isWebAuthnSupported()) { - setError("WebAuthn is not supported by your browser."); - setIsLoading(false); - return; - } - - try { - // Step 1: Request a registration challenge from the server - // The server generates a random challenge and credential creation options - // including information like: - // - relying party (website) details - // - user account information - // - challenge to prevent replay attacks - // - supported algorithms - const response = await nhost.auth.signUpWebauthn({ - email, - options: { - displayName, - }, - }); - - // Store the challenge data for UI feedback - setChallengeData(response.body); - - try { - // Step 2: Browser prompts user to create a new credential - // This activates the authenticator (fingerprint scanner, security key, etc.) - // and creates a new public/private key pair - // - The private key is stored securely on the device - // - The public key will be sent to the server - const credential = await startRegistration({ - optionsJSON: response.body, - }); - - if (!credential) { - setError("No credential was created."); - setIsLoading(false); - return; - } - - // Step 3: Send the credential attestation to the server for verification - // The server verifies the attestation signature and certificate chain, - // then stores the public key for future authentication attempts - const verifyResponse = await nhost.auth.verifySignUpWebauthn({ - credential, - options: { - displayName: displayName || undefined, - }, - nickname: keyNickname || `Security Key for ${displayName || email}`, - }); - - // Step 4: Handle registration success - if (verifyResponse.body?.session) { - // Success! User is now registered and authenticated - // At this point: - // - The user account has been created in the system - // - The public key is stored in the database - // - The private key remains securely on the user's device - // - A session has been established - window.location.href = - redirectTo || `${window.location.origin}/profile`; - } - } catch (credError) { - setError( - `WebAuthn registration failed: ${(credError as Error).message || "Unknown error"}`, - ); - } - } catch (err) { - const error = err as FetchError; - setError(`An error occurred during WebAuthn sign up: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - return ( -
-
- - setDisplayName(e.target.value)} - /> -
- -
- - setEmail(e.target.value)} - required - /> -
- -
- - setKeyNickname(e.target.value)} - placeholder="My Security Key" - /> -

- A friendly name for your security key -

-
- - {error &&
{error}
} - - - -
-

- You'll be prompted to use your device's security key (like - TouchID, FaceID, Windows Hello, or a USB security key) -

-

- When prompted, please complete the biometric verification or insert - and activate your security key to create your account. -

-
-
- ); -} diff --git a/examples/demos/react-demo/src/index.css b/examples/demos/react-demo/src/index.css deleted file mode 100644 index 5ccf16be3..000000000 --- a/examples/demos/react-demo/src/index.css +++ /dev/null @@ -1,756 +0,0 @@ -/* Base styles */ -:root { - --background: #030712; - --foreground: #ffffff; - --card-bg: #111827; - --card-border: #1f2937; - --primary: #6366f1; - --primary-hover: #4f46e5; - --secondary: #10b981; - --secondary-hover: #059669; - --accent: #8b5cf6; - --accent-hover: #7c3aed; - --success: #22c55e; - --error: #ef4444; - --text-primary: #f9fafb; - --text-secondary: #d1d5db; - --text-muted: #9ca3af; - --border-color: rgba(31, 41, 55, 0.7); - --font-geist-mono: - ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", - "Courier New", monospace; -} - -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - background: var(--background); - color: var(--foreground); - font-family: system-ui, -apple-system, sans-serif; - line-height: 1.6; - min-height: 100vh; -} - -/* Layout */ -.flex { - display: flex; -} - -.flex-col { - flex-direction: column; -} - -.items-center { - align-items: center; -} - -.justify-center { - justify-content: center; -} - -.justify-between { - justify-content: space-between; -} - -.min-h-screen { - min-height: 100vh; -} - -.w-full { - width: 100%; -} - -.max-w-2xl { - max-width: 42rem; -} - -.mx-auto { - margin-left: auto; - margin-right: auto; -} - -.p-6 { - padding: 1.5rem; -} - -.p-8 { - padding: 2rem; -} - -.py-5 { - padding-top: 1.25rem; - padding-bottom: 1.25rem; -} - -.mb-6 { - margin-bottom: 1.5rem; -} - -.mb-4 { - margin-bottom: 1rem; -} - -.mt-4 { - margin-top: 1rem; -} - -.mr-8 { - margin-right: 2rem; -} - -.ml-2 { - margin-left: 0.5rem; -} - -.space-y-5 > * + * { - margin-top: 1.25rem; -} - -.space-x-4 > * + * { - margin-left: 1rem; -} - -/* Typography */ -h1, -h2, -h3 { - font-weight: bold; - line-height: 1.2; -} - -.text-3xl { - font-size: 1.875rem; -} - -.text-2xl { - font-size: 1.5rem; -} - -.text-xl { - font-size: 1.25rem; -} - -.text-lg { - font-size: 1.125rem; -} - -.text-sm { - font-size: 0.875rem; -} - -.text-xs { - font-size: 0.75rem; -} - -.font-bold { - font-weight: 700; -} - -.font-semibold { - font-weight: 600; -} - -.font-medium { - font-weight: 500; -} - -.text-center { - text-align: center; -} - -.gradient-text { - background: linear-gradient(to right, var(--primary), var(--accent)); - -webkit-background-clip: text; - background-clip: text; - color: transparent; -} - -/* Components */ -.glass-card { - background: rgba(17, 24, 39, 0.7); - backdrop-filter: blur(8px); - border: 1px solid var(--border-color); - border-radius: 0.5rem; - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2); -} - -.btn { - display: inline-block; - padding: 0.625rem 1rem; - font-weight: 500; - border-radius: 0.375rem; - transition: all 0.2s ease; - cursor: pointer; - text-align: center; - border: none; -} - -.btn-primary { - background-color: var(--primary); - color: white; -} - -.btn-primary:hover:not(:disabled) { - background-color: var(--primary-hover); - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1); -} - -.btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.btn-secondary { - background-color: var(--secondary); - color: white; -} - -.btn-secondary:hover:not(:disabled) { - background-color: var(--secondary-hover); -} - -.nav-link { - display: inline-block; - padding: 0.5rem 1rem; - border-radius: 0.375rem; - font-weight: 600; - font-size: 0.875rem; - transition: all 0.2s ease; - color: var(--text-secondary); - text-decoration: none; -} - -.nav-link:hover { - color: white; - background-color: rgba(31, 41, 55, 0.7); -} - -.nav-link.active { - background-color: var(--primary); - color: white; - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.3); -} - -input, -textarea, -select { - width: 100%; - padding: 0.625rem 0.75rem; - background-color: rgba(31, 41, 55, 0.8); - border: 1px solid var(--border-color); - color: white; - border-radius: 0.375rem; - transition: all 0.2s; -} - -input:focus, -textarea:focus, -select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2); -} - -label { - display: block; - margin-bottom: 0.25rem; - font-size: 0.875rem; - font-weight: 500; - color: var(--text-secondary); -} - -.alert { - padding: 0.75rem; - border-radius: 0.375rem; - margin-bottom: 1rem; -} - -.alert-error { - background-color: rgba(239, 68, 68, 0.2); - border: 1px solid rgba(239, 68, 68, 0.5); - color: white; -} - -.alert-success { - background-color: rgba(34, 197, 94, 0.2); - border: 1px solid rgba(34, 197, 94, 0.5); - color: white; -} - -/* Navigation */ -.navbar { - position: sticky; - top: 0; - z-index: 10; - background-color: rgba(17, 24, 39, 0.8); - backdrop-filter: blur(8px); - border-bottom: 1px solid var(--border-color); - padding: 1rem 0; - margin-bottom: 2rem; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); -} - -.navbar-container { - display: flex; - justify-content: space-between; - align-items: center; - max-width: 42rem; - margin: 0 auto; - padding: 0 1.5rem; -} - -.navbar-brand { - color: var(--primary); - font-weight: bold; - font-size: 1.125rem; - margin-right: 2rem; -} - -.navbar-links { - display: flex; - gap: 1rem; -} - -/* Tables */ -table { - width: 100%; - border-collapse: collapse; -} - -th { - text-align: left; - padding: 0.75rem 1rem; - font-size: 0.75rem; - text-transform: uppercase; - color: var(--text-secondary); - border-bottom: 1px solid var(--border-color); -} - -td { - padding: 0.75rem 1rem; - border-bottom: 1px solid var(--border-color); - font-size: 0.875rem; -} - -tr:hover { - background-color: rgba(31, 41, 55, 0.3); -} - -/* File upload styles */ -.file-upload { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 1.5rem; - border: 2px dashed rgba(99, 102, 241, 0.3); - border-radius: 0.5rem; - background-color: rgba(31, 41, 55, 0.3); - cursor: pointer; - transition: all 0.2s; - width: 100%; - font: inherit; - color: inherit; - text-align: center; -} - -.file-upload:hover { - border-color: var(--primary); -} - -/* Footer */ -footer { - padding: 1.25rem 0; - border-top: 1px solid var(--border-color); - display: flex; - justify-content: center; - align-items: center; -} - -/* Link styles */ -a { - color: var(--primary); - text-decoration: none; - transition: color 0.2s; -} - -a:hover { - color: var(--primary-hover); - text-decoration: underline; -} - -/* Loading state */ -.loading-container { - display: flex; - justify-content: center; - align-items: center; - min-height: 50vh; -} - -/* Code blocks */ -pre { - background-color: rgba(31, 41, 55, 0.8); - padding: 1rem; - border-radius: 0.375rem; - overflow: auto; - font-family: monospace; - border: 1px solid var(--border-color); - font-size: 0.875rem; - color: var(--text-secondary); -} - -/* Profile data */ -.profile-item { - padding-bottom: 0.75rem; - margin-bottom: 0.75rem; - border-bottom: 1px solid var(--border-color); -} - -.profile-item strong { - color: var(--text-secondary); -} - -.action-link { - color: var(--primary); - font-weight: 500; - margin-right: 0.75rem; - cursor: pointer; -} - -.action-link:hover { - color: var(--primary-hover); - text-decoration: underline; -} - -.action-link-danger { - color: var(--error); -} - -.action-link-danger:hover { - color: #f05252; -} - -/* Icon button */ -.icon-button { - background-color: transparent; - color: var(--primary); - width: 40px; - height: 40px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - border: none; - transition: all 0.2s; -} - -.icon-button:hover { - background-color: rgba(99, 102, 241, 0.1); - color: var(--primary-hover); -} - -.icon-button:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.icon-button svg { - width: 20px; - height: 20px; -} - -/* Table action icons */ -.table-actions { - display: flex; - gap: 8px; -} - -.action-icon { - background-color: transparent; - border: none; - width: 32px; - height: 32px; - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all 0.2s; - padding: 0; -} - -.action-icon svg { - width: 18px; - height: 18px; -} - -.action-icon:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.action-icon-view { - color: var(--primary); -} - -.action-icon-view:hover:not(:disabled) { - background-color: rgba(99, 102, 241, 0.1); - color: var(--primary-hover); -} - -.action-icon-delete { - color: var(--error); -} - -.action-icon-delete:hover:not(:disabled) { - background-color: rgba(239, 68, 68, 0.1); - color: #f05252; -} - -/* Tab styles */ -.tabs-container { - display: flex; - border-radius: 0.5rem; - overflow: hidden; - margin-bottom: 1.5rem; - border: 1px solid var(--border-color); -} - -.tab-button { - flex: 1; - padding: 0.75rem 1rem; - font-weight: 500; - transition: all 0.2s ease; - background-color: rgba(31, 41, 55, 0.5); - color: var(--text-secondary); -} - -.tab-button:hover:not(.tab-active) { - background-color: rgba(31, 41, 55, 0.8); - color: var(--text-primary); -} - -.tab-button.tab-active { - background-color: var(--primary); - color: white; - box-shadow: 0 0 0 1px rgba(99, 102, 241, 0.3); -} - -.tab-button:first-child { - border-top-left-radius: 0.5rem; - border-bottom-left-radius: 0.5rem; -} - -.tab-button:last-child { - border-top-right-radius: 0.5rem; - border-bottom-right-radius: 0.5rem; -} - -.tab-content { - margin-top: 1.5rem; -} - -/* Additional utility classes */ -.w-4 { - width: 1rem; -} -.w-5 { - width: 1.25rem; -} -.w-6 { - width: 1.5rem; -} -.w-16 { - width: 4rem; -} -.h-4 { - height: 1rem; -} -.h-5 { - height: 1.25rem; -} -.h-6 { - height: 1.5rem; -} -.h-16 { - height: 4rem; -} -.mr-2 { - margin-right: 0.5rem; -} -.mb-2 { - margin-bottom: 0.5rem; -} -.mb-3 { - margin-bottom: 0.75rem; -} -.pt-3 { - padding-top: 0.75rem; -} -.p-3 { - padding: 0.75rem; -} -.space-x-1 > * + * { - margin-left: 0.25rem; -} -.space-x-2 > * + * { - margin-left: 0.5rem; -} -.space-x-3 > * + * { - margin-left: 0.75rem; -} -.space-y-4 > * + * { - margin-top: 1rem; -} -.flex-1 { - flex: 1; -} -.inline-block { - display: inline-block; -} -.leading-relaxed { - line-height: 1.625; -} -.rounded { - border-radius: 0.375rem; -} -.rounded-full { - border-radius: 9999px; -} -.border { - border-width: 1px; -} -.border-2 { - border-width: 2px; -} -.border-t { - border-top-width: 1px; -} -.border-t-transparent { - border-top-color: transparent; -} -.opacity-75 { - opacity: 0.75; -} -.line-through { - text-decoration-line: line-through; -} -.cursor-pointer { - cursor: pointer; -} -.transition-all { - transition-property: all; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} -.duration-200 { - transition-duration: 200ms; -} -.hover\:shadow-lg:hover { - box-shadow: - 0 10px 15px -3px rgba(0, 0, 0, 0.1), - 0 4px 6px -2px rgba(0, 0, 0, 0.05); -} -.hover\:border-secondary:hover { - border-color: var(--secondary); -} - -/* Color utilities using CSS variables */ -.text-primary { - color: var(--text-primary); -} -.text-secondary { - color: var(--text-secondary); -} -.text-muted { - color: var(--text-muted); -} -.bg-card-bg { - background-color: var(--card-bg); -} -.border-border-color { - border-color: var(--border-color); -} -.bg-secondary { - background-color: var(--secondary); -} -.border-secondary { - border-color: var(--secondary); -} -.border-primary { - border-color: var(--primary); -} - -/* Spinning animation */ -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -.animate-spin { - animation: spin 1s linear infinite; -} - -/* Floating Add Button */ -.add-todo-btn { - width: 60px; - height: 60px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 24px; - box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3); - transition: all 0.3s ease; -} - -.add-todo-btn:hover { - transform: scale(1.05); - box-shadow: 0 6px 16px rgba(99, 102, 241, 0.4); -} - -/* Small Add Button */ -.add-todo-btn-small { - width: 32px; - height: 32px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 2px 8px rgba(99, 102, 241, 0.2); - transition: all 0.2s ease; -} - -.add-todo-btn-small:hover { - transform: scale(1.1); - box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3); -} - -/* Text-only Add Button */ -.add-todo-text-btn { - background: none; - border: none; - color: var(--primary); - cursor: pointer; - transition: all 0.2s ease; - display: flex; - align-items: center; - justify-content: center; - padding: 4px; -} - -.add-todo-text-btn:hover { - color: var(--primary-hover); - transform: scale(1.1); -} - -/* Todo title hover effect */ -.hover\:text-primary-hover:hover { - color: var(--primary-hover); -} diff --git a/examples/demos/react-demo/src/lib/nhost/AuthProvider.tsx b/examples/demos/react-demo/src/lib/nhost/AuthProvider.tsx deleted file mode 100644 index d00eff867..000000000 --- a/examples/demos/react-demo/src/lib/nhost/AuthProvider.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import { createClient, type NhostClient } from "@nhost/nhost-js"; -import type { Session } from "@nhost/nhost-js/auth"; -import { - createContext, - type ReactNode, - useCallback, - useContext, - useEffect, - useMemo, - useRef, - useState, -} from "react"; - -/** - * Authentication context interface providing access to user session state and Nhost client. - * Used throughout the React application to access authentication-related data and operations. - */ -interface AuthContextType { - /** Current authenticated user object, null if not authenticated */ - user: Session["user"] | null; - /** Current session object containing tokens and user data, null if no active session */ - session: Session | null; - /** Boolean indicating if user is currently authenticated */ - isAuthenticated: boolean; - /** Boolean indicating if authentication state is still loading */ - isLoading: boolean; - /** Nhost client instance for making authenticated requests */ - nhost: NhostClient; -} - -// Create React context for authentication state and nhost client -const AuthContext = createContext(null); - -interface AuthProviderProps { - children: ReactNode; -} - -/** - * AuthProvider component that provides authentication context to the React application. - * - * This component handles: - * - Initializing the Nhost client with default EventEmitterStorage - * - Managing authentication state (user, session, loading, authenticated status) - * - Cross-tab session synchronization using sessionStorage.onChange events - * - Page visibility and focus event handling to maintain session consistency - * - Client-side only session management (no server-side rendering) - */ -export const AuthProvider = ({ children }: AuthProviderProps) => { - const [user, setUser] = useState(null); - const [session, setSession] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [isAuthenticated, setIsAuthenticated] = useState(false); - const lastRefreshTokenIdRef = useRef(null); - - // Initialize Nhost client with default SessionStorage (local storage) - const nhost = useMemo( - () => - createClient({ - region: import.meta.env.VITE_NHOST_REGION || "local", - subdomain: import.meta.env.VITE_NHOST_SUBDOMAIN || "local", - }), - [], - ); - - /** - * Handles session reload when refresh token changes. - * This detects when the session has been updated from other tabs. - * Unlike the Next.js version, this only updates local state without server synchronization. - * - * @param currentRefreshTokenId - The current refresh token ID to compare against stored value - */ - const reloadSession = useCallback( - (currentRefreshTokenId: string | null) => { - if (currentRefreshTokenId !== lastRefreshTokenIdRef.current) { - lastRefreshTokenIdRef.current = currentRefreshTokenId; - - // Update local authentication state to match current session - const currentSession = nhost.getUserSession(); - setUser(currentSession?.user || null); - setSession(currentSession); - setIsAuthenticated(!!currentSession); - } - }, - [nhost], - ); - - // Initialize authentication state and set up cross-tab session synchronization - useEffect(() => { - setIsLoading(true); - - // Load initial session state from Nhost client - const currentSession = nhost.getUserSession(); - setUser(currentSession?.user || null); - setSession(currentSession); - setIsAuthenticated(!!currentSession); - lastRefreshTokenIdRef.current = currentSession?.refreshTokenId ?? null; - setIsLoading(false); - - // Subscribe to session changes from other browser tabs - // This enables real-time synchronization when user signs in/out in another tab - const unsubscribe = nhost.sessionStorage.onChange((session) => { - reloadSession(session?.refreshTokenId ?? null); - }); - - return unsubscribe; - }, [nhost, reloadSession]); - - // Handle session changes from page focus events (for additional session consistency) - useEffect(() => { - /** - * Checks for session changes when page becomes visible or focused. - * In the React SPA context, this provides additional consistency checks - * though it's less critical than in the Next.js SSR version. - */ - const checkSessionOnFocus = () => { - reloadSession(nhost.getUserSession()?.refreshTokenId ?? null); - }; - - // Monitor page visibility changes (tab switching, window minimizing) - document.addEventListener("visibilitychange", () => { - if (!document.hidden) { - checkSessionOnFocus(); - } - }); - - // Monitor window focus events (clicking back into the browser window) - window.addEventListener("focus", checkSessionOnFocus); - - // Cleanup event listeners on component unmount - return () => { - document.removeEventListener("visibilitychange", checkSessionOnFocus); - window.removeEventListener("focus", checkSessionOnFocus); - }; - }, [nhost, reloadSession]); - - const value: AuthContextType = { - user, - session, - isAuthenticated, - isLoading, - nhost, - }; - - return {children}; -}; - -/** - * Custom hook to access the authentication context. - * - * Must be used within a component wrapped by AuthProvider. - * Provides access to current user session, authentication state, and Nhost client. - * - * @throws {Error} When used outside of AuthProvider - * @returns {AuthContextType} Authentication context containing user, session, and client - * - * @example - * ```tsx - * function MyComponent() { - * const { user, isAuthenticated, nhost } = useAuth(); - * - * if (!isAuthenticated) { - * return
Please sign in
; - * } - * - * return
Welcome, {user?.displayName}!
; - * } - * ``` - */ -export const useAuth = (): AuthContextType => { - const context = useContext(AuthContext); - if (!context) { - throw new Error("useAuth must be used within an AuthProvider"); - } - return context; -}; diff --git a/examples/demos/react-demo/src/lib/utils.ts b/examples/demos/react-demo/src/lib/utils.ts deleted file mode 100644 index e8560a922..000000000 --- a/examples/demos/react-demo/src/lib/utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Format file size in a readable way -export function formatFileSize(bytes: number): string { - if (bytes === 0) return "0 Bytes"; - - const sizes: string[] = ["Bytes", "KB", "MB", "GB", "TB"]; - const i: number = Math.floor(Math.log(bytes) / Math.log(1024)); - - return `${parseFloat((bytes / 1024 ** i).toFixed(2))} ${sizes[i]}`; -} - -/** - * Checks if WebAuthn (FIDO2) authentication is supported in the current browser - * - * WebAuthn requires: - * 1. A secure context (HTTPS or localhost) - * 2. The PublicKeyCredential API - * 3. The navigator.credentials API - * - * This function determines if the current environment can support passwordless - * authentication using security keys or platform authenticators (e.g., Touch ID, - * Face ID, Windows Hello, or FIDO security keys). - * - * Note: Even if this returns true, the user still needs to have an authenticator - * (biometric sensor, security key) available on their device. - * - * @returns {boolean} Whether WebAuthn is supported in the current environment - */ -export const isWebAuthnSupported = (): boolean => { - return ( - typeof window !== "undefined" && - !!window.PublicKeyCredential && - !!navigator.credentials - ); -}; diff --git a/examples/demos/react-demo/src/main.tsx b/examples/demos/react-demo/src/main.tsx deleted file mode 100644 index b53875ea4..000000000 --- a/examples/demos/react-demo/src/main.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; -import { createRoot } from "react-dom/client"; -import "./index.css"; -import App from "./App"; - -const rootElement = document.getElementById("root"); -if (!rootElement) throw new Error("Root element not found"); - -createRoot(rootElement).render( - - - , -); diff --git a/examples/demos/react-demo/src/pages/Home.tsx b/examples/demos/react-demo/src/pages/Home.tsx deleted file mode 100644 index b6e80a137..000000000 --- a/examples/demos/react-demo/src/pages/Home.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { JSX } from "react"; -import { Navigate } from "react-router-dom"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -export default function Home(): JSX.Element { - const { isAuthenticated, isLoading } = useAuth(); - - // If authentication is still loading, show a loading state - if (isLoading) { - return ( -
-

Loading...

-
- ); - } - - // Redirect based on authentication status - if (isAuthenticated) { - return ; - } - - // If not authenticated, redirect to signin page - return ; -} diff --git a/examples/demos/react-demo/src/pages/Profile.tsx b/examples/demos/react-demo/src/pages/Profile.tsx deleted file mode 100644 index da8dbfa16..000000000 --- a/examples/demos/react-demo/src/pages/Profile.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError, FetchResponse } from "@nhost/nhost-js/fetch"; -import type { JSX } from "react"; -import { useEffect, useState } from "react"; -import ChangePassword from "../components/ChangePassword"; -import MFASettings from "../components/MFASettings"; -import SecurityKeys from "../components/SecurityKeys"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface MfaStatusResponse { - data?: { - user?: { - activeMfaType: string | null; - }; - }; -} - -export default function Profile(): JSX.Element { - const { nhost, user, session, isAuthenticated } = useAuth(); - const [isMfaEnabled, setIsMfaEnabled] = useState(false); - - // Fetch MFA status when user is authenticated - useEffect(() => { - const fetchMfaStatus = async (): Promise => { - if (!user?.id) return; - - try { - // Correctly structure GraphQL query with parameters - const response: FetchResponse = - await nhost.graphql.request({ - query: ` - query GetUserMfaStatus($userId: uuid!) { - user(id: $userId) { - activeMfaType - } - } - `, - variables: { - userId: user.id, - }, - }); - - const userData = response.body?.data; - const activeMfaType = userData?.user?.activeMfaType; - const newMfaEnabled = activeMfaType === "totp"; - - // Update the state - setIsMfaEnabled(newMfaEnabled); - } catch (err) { - const error = err as FetchError; - console.error(`Failed to query MFA status: ${error.message}`); - } - }; - - if (isAuthenticated && user?.id) { - fetchMfaStatus(); - } - }, [user, isAuthenticated, nhost.graphql]); - - // ProtectedRoute component now handles authentication check - // We can just focus on the component logic here - - return ( -
-

Your Profile

- -
-
-
- Display Name: - {user?.displayName || "Not set"} -
- -
- Email: - {user?.email || "Not available"} -
- -
- User ID: - - {user?.id || "Not available"} - -
- -
- Roles: - {user?.roles?.join(", ") || "None"} -
- -
- Email Verified: - {user?.emailVerified ? "Yes" : "No"} -
-
-
- -
-

Session Information

-
{JSON.stringify(session, null, 2)}
-
- - - - - - -
- ); -} diff --git a/examples/demos/react-demo/src/pages/SignIn.tsx b/examples/demos/react-demo/src/pages/SignIn.tsx deleted file mode 100644 index fae6729f3..000000000 --- a/examples/demos/react-demo/src/pages/SignIn.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { type JSX, useEffect, useId, useState } from "react"; -import { Link, useLocation, useNavigate } from "react-router-dom"; -import MagicLinkForm from "../components/MagicLinkForm"; -import TabForm from "../components/TabForm"; -import WebAuthnSignInForm from "../components/WebAuthnSignInForm"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -export default function SignIn(): JSX.Element { - const { nhost, isAuthenticated } = useAuth(); - const navigate = useNavigate(); - const location = useLocation(); - const params = new URLSearchParams(location.search); - - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState( - params.get("error") || null, - ); - const emailId = useId(); - const passwordId = useId(); - - const magicLinkSent = params.get("magic") === "success"; - const isVerifying = params.has("fromVerify"); - - // Use useEffect for navigation after authentication is confirmed - useEffect(() => { - if (isAuthenticated && !isVerifying) { - navigate("/profile"); - } - }, [isAuthenticated, isVerifying, navigate]); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setIsLoading(true); - setError(null); - - try { - // Use the signIn function from auth context - const response = await nhost.auth.signInEmailPassword({ - email, - password, - }); - - // Check if MFA is required - if (response.body?.mfa) { - navigate(`/signin/mfa?ticket=${response.body.mfa.ticket}`); - return; - } - - // If we have a session, sign in was successful - if (response.body?.session) { - navigate("/profile"); - } else { - setError("Failed to sign in"); - } - } catch (err) { - const error = err as FetchError; - setError(`An error occurred during sign in: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - const handleSocialSignIn = (provider: "github") => { - // Get the current origin (to build the redirect URL) - const origin = window.location.origin; - const redirectUrl = `${origin}/verify`; - - // Sign in with the specified provider - const url = nhost.auth.signInProviderURL(provider, { - redirectTo: redirectUrl, - }); - - window.location.href = url; - }; - - return ( -
-

Nhost SDK Demo

- -
-

Sign In

- - {magicLinkSent ? ( -
-

- Magic link sent! Check your email to sign in. -

- - Back to sign in - -
- ) : ( - -
- - setEmail(e.target.value)} - required - /> -
- -
- - setPassword(e.target.value)} - required - /> -
- - {error &&
{error}
} - - - - } - magicTabContent={ -
- -
- } - socialTabContent={ -
-

Sign in using your Social account

- -
- } - webauthnTabContent={} - /> - )} -
- -
-

- Don't have an account? Sign Up -

-
-
- ); -} diff --git a/examples/demos/react-demo/src/pages/SignUp.tsx b/examples/demos/react-demo/src/pages/SignUp.tsx deleted file mode 100644 index a785775fd..000000000 --- a/examples/demos/react-demo/src/pages/SignUp.tsx +++ /dev/null @@ -1,210 +0,0 @@ -import type { ErrorResponse } from "@nhost/nhost-js/auth"; -import type { FetchError } from "@nhost/nhost-js/fetch"; -import { type JSX, useId, useState } from "react"; -import { Link, Navigate, useNavigate } from "react-router-dom"; -import MagicLinkForm from "../components/MagicLinkForm"; -import TabForm from "../components/TabForm"; -import WebAuthnSignUpForm from "../components/WebAuthnSignUpForm"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -export default function SignUp(): JSX.Element { - const { nhost, isAuthenticated } = useAuth(); - const navigate = useNavigate(); - - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [displayName, setDisplayName] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [success, setSuccess] = useState(false); - const displayNameId = useId(); - const emailId = useId(); - const passwordId = useId(); - - // If already authenticated, redirect to profile - if (isAuthenticated) { - return ; - } - - const handleSubmit = async ( - e: React.FormEvent, - ): Promise => { - e.preventDefault(); - setIsLoading(true); - setError(null); - setSuccess(false); - - try { - const response = await nhost.auth.signUpEmailPassword({ - email, - password, - options: { - displayName, - redirectTo: `${window.location.origin}/verify`, - }, - }); - - if (response.body?.session) { - // Successfully signed up and automatically signed in - navigate("/profile"); - } else { - // Verification email sent or user created but needs verification - setSuccess(true); - } - } catch (err) { - const error = err as FetchError; - setError(`An error occurred during sign up: ${error.message}`); - } finally { - setIsLoading(false); - } - }; - - const handleSocialSignIn = (provider: "github") => { - // Get the current origin (to build the redirect URL) - const origin = window.location.origin; - const redirectUrl = `${origin}/verify`; - - // Sign in with the specified provider - const url = nhost.auth.signInProviderURL(provider, { - redirectTo: redirectUrl, - }); - - window.location.href = url; - }; - - if (success) { - return ( -
-

Nhost SDK Demo

- -
-

Check Your Email

- -
-
-

- We've sent a verification link to {email} -

-

- Please check your email and click the verification link to - activate your account. -

-
- - -
-
-
- ); - } - - return ( -
-

Nhost SDK Demo

- -
-

Sign Up

- - -
- - setDisplayName(e.target.value)} - /> -
- -
- - setEmail(e.target.value)} - required - /> -
- -
- - setPassword(e.target.value)} - required - /> -

- Password must be at least 8 characters long -

-
- - {error &&
{error}
} - - - - } - magicTabContent={ -
- -
- } - socialTabContent={ -
-

Sign up using your Social account

- -
- } - webauthnTabContent={ - - } - /> -
- -
-

- Already have an account? Sign In -

-
-
- ); -} diff --git a/examples/demos/react-demo/src/pages/Todos.tsx b/examples/demos/react-demo/src/pages/Todos.tsx deleted file mode 100644 index 87d90e42a..000000000 --- a/examples/demos/react-demo/src/pages/Todos.tsx +++ /dev/null @@ -1,648 +0,0 @@ -import type { JSX } from "react"; -import { useCallback, useEffect, useId, useState } from "react"; -import { useAuth } from "../lib/nhost/AuthProvider"; - -interface Todo { - id: string; - title: string; - details: string | null; - completed: boolean; - created_at: string; - updated_at: string; - user_id: string; -} - -interface GetTodos { - todos: Todo[]; -} - -interface InsertTodo { - insert_todos_one: Todo | null; -} - -interface UpdateTodo { - update_todos_by_pk: Todo | null; -} - -export default function Todos(): JSX.Element { - const { nhost, session } = useAuth(); - const [todos, setTodos] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [newTodoTitle, setNewTodoTitle] = useState(""); - const [newTodoDetails, setNewTodoDetails] = useState(""); - const [editingTodo, setEditingTodo] = useState(null); - const [showAddForm, setShowAddForm] = useState(false); - const [expandedTodos, setExpandedTodos] = useState>(new Set()); - - const titleId = useId(); - const detailsId = useId(); - - const fetchTodos = useCallback(async () => { - try { - setLoading(true); - const response = await nhost.graphql.request({ - query: ` - query GetTodos { - todos(order_by: { created_at: desc }) { - id - title - details - completed - created_at - updated_at - user_id - } - } - `, - }); - - if (response.body.errors) { - throw new Error( - response.body.errors[0]?.message || "Failed to fetch todos", - ); - } - - setTodos(response.body?.data?.todos || []); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "Failed to fetch todos"); - } finally { - setLoading(false); - } - }, [nhost.graphql]); - - const addTodo = async (e: React.FormEvent) => { - e.preventDefault(); - if (!newTodoTitle.trim()) return; - - try { - const response = await nhost.graphql.request({ - query: ` - mutation InsertTodo($title: String!, $details: String) { - insert_todos_one(object: { title: $title, details: $details }) { - id - title - details - completed - created_at - updated_at - user_id - } - } - `, - variables: { - title: newTodoTitle.trim(), - details: newTodoDetails.trim() || null, - }, - }); - - if (response.body.errors) { - throw new Error( - response.body.errors[0]?.message || "Failed to add todo", - ); - } - - if (!response.body?.data?.insert_todos_one) { - throw new Error("Failed to add todo"); - } - setTodos([response.body?.data?.insert_todos_one, ...todos]); - setNewTodoTitle(""); - setNewTodoDetails(""); - setShowAddForm(false); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "Failed to add todo"); - } - }; - - const updateTodo = async ( - id: string, - updates: Partial>, - ) => { - try { - const response = await nhost.graphql.request({ - query: ` - mutation UpdateTodo($id: uuid!, $updates: todos_set_input!) { - update_todos_by_pk(pk_columns: { id: $id }, _set: $updates) { - id - title - details - completed - created_at - updated_at - user_id - } - } - `, - variables: { - id, - updates, - }, - }); - - if (response.body.errors) { - throw new Error( - response.body.errors[0]?.message || "Failed to update todo", - ); - } - - if (!response.body?.data?.update_todos_by_pk) { - throw new Error("Failed to update todo"); - } - - const updatedTodo = response.body?.data?.update_todos_by_pk; - if (updatedTodo) { - setTodos(todos.map((todo) => (todo.id === id ? updatedTodo : todo))); - } - setEditingTodo(null); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "Failed to update todo"); - } - }; - - const deleteTodo = async (id: string) => { - if (!confirm("Are you sure you want to delete this todo?")) return; - - try { - const response = await nhost.graphql.request({ - query: ` - mutation DeleteTodo($id: uuid!) { - delete_todos_by_pk(id: $id) { - id - } - } - `, - variables: { - id, - }, - }); - - if (response.body.errors) { - throw new Error( - response.body.errors[0]?.message || "Failed to delete todo", - ); - } - - setTodos(todos.filter((todo) => todo.id !== id)); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "Failed to delete todo"); - } - }; - - const toggleComplete = async (todo: Todo) => { - await updateTodo(todo.id, { completed: !todo.completed }); - }; - - const saveEdit = async () => { - if (!editingTodo) return; - await updateTodo(editingTodo.id, { - title: editingTodo.title, - details: editingTodo.details, - }); - }; - - const toggleTodoExpansion = (todoId: string) => { - const newExpanded = new Set(expandedTodos); - if (newExpanded.has(todoId)) { - newExpanded.delete(todoId); - } else { - newExpanded.add(todoId); - } - setExpandedTodos(newExpanded); - }; - - useEffect(() => { - if (session) { - fetchTodos(); - } - }, [session, fetchTodos]); - - if (!session) { - return ( -
-

Please sign in to view your todos.

-
- ); - } - - return ( -
-
-

My Todos

- {!showAddForm && ( - - )} -
- - {error && ( -
- Error: {error} -
- )} - - {/* Add new todo form */} - {showAddForm && ( -
-
-
-

Add New Todo

- -
-
-
- - setNewTodoTitle(e.target.value)} - placeholder="What needs to be done?" - required - /> -
-
- - -
-
- - -
-
-
-
- {/if} - - {#if !showAddForm} - {#if loading} -
-
-
- Loading todos... -
-
- {:else} -
- {#if todos.length === 0} -
- -

No todos yet

-

- Create your first todo to get started! -

-
- {:else} - {#each todos as todo (todo.id)} -
- {#if editingTodo?.id === todo.id} -
-
-
- - -
-
- - -
-
- - -
-
-
- {:else} -
-
- -
- - - -
-
- - {#if expandedTodos.has(todo.id)} -
- {#if todo.details} -
-

{todo.details}

-
- {/if} - -
-
- - Created: {new Date(todo.created_at).toLocaleString()} - - - Updated: {new Date(todo.updated_at).toLocaleString()} - -
- {#if todo.completed} -
- - Completed -
- {/if} -
-
- {/if} -
- {/if} -
- {/each} - {/if} -
- {/if} - {/if} -
-{/if} diff --git a/examples/tutorials/nhost-svelte-tutorial/src/routes/verify/+page.svelte b/examples/tutorials/nhost-svelte-tutorial/src/routes/verify/+page.svelte deleted file mode 100644 index 0bbcd6f8a..000000000 --- a/examples/tutorials/nhost-svelte-tutorial/src/routes/verify/+page.svelte +++ /dev/null @@ -1,153 +0,0 @@ - - -
-

Email Verification

- -
- {#if status === "verifying"} -
-

Verifying your email...

-
-
- {/if} - - {#if status === "success"} -
-

- ✓ Successfully verified! -

-

You'll be redirected to your profile page shortly...

-
- {/if} - - {#if status === "error"} -
-

- Verification failed -

-

{error}

- - {#if Object.keys(urlParams).length > 0} -
-

- URL Parameters: -

- {#each Object.entries(urlParams) as [key, value] (key)} -
- - {key}: - - {value} -
- {/each} -
- {/if} - - -
- {/if} -
-
- - diff --git a/examples/tutorials/nhost-svelte-tutorial/static/robots.txt b/examples/tutorials/nhost-svelte-tutorial/static/robots.txt deleted file mode 100644 index b6dd6670c..000000000 --- a/examples/tutorials/nhost-svelte-tutorial/static/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# allow crawling everything by default -User-agent: * -Disallow: diff --git a/examples/tutorials/nhost-svelte-tutorial/svelte.config.js b/examples/tutorials/nhost-svelte-tutorial/svelte.config.js deleted file mode 100644 index a8bb58ace..000000000 --- a/examples/tutorials/nhost-svelte-tutorial/svelte.config.js +++ /dev/null @@ -1,18 +0,0 @@ -import adapter from "@sveltejs/adapter-auto"; -import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; - -/** @type {import('@sveltejs/kit').Config} */ -const config = { - // Consult https://svelte.dev/docs/kit/integrations - // for more information about preprocessors - preprocess: vitePreprocess(), - - kit: { - // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. - // If your environment is not supported, or you settled on a specific environment, switch out the adapter. - // See https://svelte.dev/docs/kit/adapters for more information about adapters. - adapter: adapter(), - }, -}; - -export default config; diff --git a/examples/tutorials/nhost-svelte-tutorial/tsconfig.json b/examples/tutorials/nhost-svelte-tutorial/tsconfig.json deleted file mode 100644 index e3898cb22..000000000 --- a/examples/tutorials/nhost-svelte-tutorial/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "moduleResolution": "bundler" - } - // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias - // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files - // - // To make changes to top-level options such as include and exclude, we recommend extending - // the generated config; see https://svelte.dev/docs/kit/configuration#typescript -} diff --git a/examples/tutorials/nhost-svelte-tutorial/vite.config.ts b/examples/tutorials/nhost-svelte-tutorial/vite.config.ts deleted file mode 100644 index 80864b9de..000000000 --- a/examples/tutorials/nhost-svelte-tutorial/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sveltekit } from "@sveltejs/kit/vite"; -import { defineConfig } from "vite"; - -export default defineConfig({ - plugins: [sveltekit()], -}); diff --git a/examples/tutorials/nhost-vue-tutorial/.gitignore b/examples/tutorials/nhost-vue-tutorial/.gitignore deleted file mode 100644 index 8ee54e8d3..000000000 --- a/examples/tutorials/nhost-vue-tutorial/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -.DS_Store -dist -dist-ssr -coverage -*.local - -/cypress/videos/ -/cypress/screenshots/ - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -*.tsbuildinfo diff --git a/examples/tutorials/nhost-vue-tutorial/.vscode/extensions.json b/examples/tutorials/nhost-vue-tutorial/.vscode/extensions.json deleted file mode 100644 index a7cea0b06..000000000 --- a/examples/tutorials/nhost-vue-tutorial/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["Vue.volar"] -} diff --git a/examples/tutorials/nhost-vue-tutorial/README.md b/examples/tutorials/nhost-vue-tutorial/README.md deleted file mode 100644 index 1bb2c7a37..000000000 --- a/examples/tutorials/nhost-vue-tutorial/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This is the result of following the tutorial at: - -https://docs.nhost.io/getting-started/tutorials/vue/1-introduction diff --git a/examples/tutorials/nhost-vue-tutorial/env.d.ts b/examples/tutorials/nhost-vue-tutorial/env.d.ts deleted file mode 100644 index 11f02fe2a..000000000 --- a/examples/tutorials/nhost-vue-tutorial/env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/examples/tutorials/nhost-vue-tutorial/index.html b/examples/tutorials/nhost-vue-tutorial/index.html deleted file mode 100644 index 9e5fc8f06..000000000 --- a/examples/tutorials/nhost-vue-tutorial/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite App - - -
- - - diff --git a/examples/tutorials/nhost-vue-tutorial/package.json b/examples/tutorials/nhost-vue-tutorial/package.json deleted file mode 100644 index 54d01cac4..000000000 --- a/examples/tutorials/nhost-vue-tutorial/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "nhost-vue-tutorial", - "version": "0.0.0", - "private": true, - "type": "module", - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "scripts": { - "dev": "vite", - "build": "vue-tsc && vite build", - "generate": "echo 'Nothing to do'", - "test": "pnpm test:typecheck && pnpm test:lint", - "test:typecheck": "vue-tsc --noEmit", - "test:lint": "biome check", - "format": "biome format --write", - "preview": "vite preview" - }, - "dependencies": { - "@nhost/nhost-js": "workspace:^", - "vue": "^3.5.18", - "vue-router": "^4.5.1" - }, - "devDependencies": { - "@tsconfig/node22": "^22.0.2", - "@types/node": "^22.16.5", - "@vitejs/plugin-vue": "^6.0.1", - "@vue/tsconfig": "^0.7.0", - "npm-run-all2": "^8.0.4", - "typescript": "~5.8.0", - "vite": "^7.0.8", - "vite-plugin-vue-devtools": "^8.0.0", - "vue-tsc": "^3.0.4" - } -} diff --git a/examples/tutorials/nhost-vue-tutorial/pnpm-lock.yaml b/examples/tutorials/nhost-vue-tutorial/pnpm-lock.yaml deleted file mode 100644 index 02428cfad..000000000 --- a/examples/tutorials/nhost-vue-tutorial/pnpm-lock.yaml +++ /dev/null @@ -1,2027 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@nhost/nhost-js': - specifier: workspace:^ - version: link:../../../packages/nhost-js - vue: - specifier: ^3.5.18 - version: 3.5.21(typescript@5.8.3) - vue-router: - specifier: ^4.5.1 - version: 4.5.1(vue@3.5.21(typescript@5.8.3)) - devDependencies: - '@tsconfig/node22': - specifier: ^22.0.2 - version: 22.0.2 - '@types/node': - specifier: ^22.16.5 - version: 22.18.3 - '@vitejs/plugin-vue': - specifier: ^6.0.1 - version: 6.0.1(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3)) - '@vue/tsconfig': - specifier: ^0.7.0 - version: 0.7.0(typescript@5.8.3)(vue@3.5.21(typescript@5.8.3)) - npm-run-all2: - specifier: ^8.0.4 - version: 8.0.4 - typescript: - specifier: ~5.8.0 - version: 5.8.3 - vite: - specifier: ^7.0.8 - version: 7.1.11(@types/node@22.18.3) - vite-plugin-vue-devtools: - specifier: ^8.0.0 - version: 8.0.2(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3)) - vue-tsc: - specifier: ^3.0.4 - version: 3.0.7(typescript@5.8.3) - -packages: - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.28.4': - resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.28.4': - resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-create-class-features-plugin@7.28.3': - resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-proposal-decorators@7.28.0': - resolution: {integrity: sha512-zOiZqvANjWDUaUS9xMxbMcK/Zccztbe/6ikvUXaG9nsPH3w6qh5UaPGAnirI/WhIbZ8m3OHU0ReyPrknG+ZKeg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-decorators@7.27.1': - resolution: {integrity: sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-import-meta@7.10.4': - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typescript@7.28.0': - resolution: {integrity: sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.4': - resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} - engines: {node: '>=6.9.0'} - - '@esbuild/aix-ppc64@0.25.9': - resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.9': - resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.9': - resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.9': - resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.9': - resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.9': - resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.9': - resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.9': - resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.9': - resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.9': - resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.9': - resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.9': - resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.9': - resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.9': - resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.9': - resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.9': - resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.9': - resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.9': - resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.9': - resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.9': - resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.9': - resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.9': - resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.9': - resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.9': - resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.9': - resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.9': - resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@polka/url@1.0.0-next.29': - resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - - '@rolldown/pluginutils@1.0.0-beta.29': - resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==} - - '@rollup/rollup-android-arm-eabi@4.50.2': - resolution: {integrity: sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.50.2': - resolution: {integrity: sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.50.2': - resolution: {integrity: sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.50.2': - resolution: {integrity: sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.50.2': - resolution: {integrity: sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.50.2': - resolution: {integrity: sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.50.2': - resolution: {integrity: sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.50.2': - resolution: {integrity: sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.50.2': - resolution: {integrity: sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.50.2': - resolution: {integrity: sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.50.2': - resolution: {integrity: sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.50.2': - resolution: {integrity: sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.50.2': - resolution: {integrity: sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.50.2': - resolution: {integrity: sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.50.2': - resolution: {integrity: sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.50.2': - resolution: {integrity: sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.50.2': - resolution: {integrity: sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openharmony-arm64@4.50.2': - resolution: {integrity: sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.50.2': - resolution: {integrity: sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.50.2': - resolution: {integrity: sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.50.2': - resolution: {integrity: sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==} - cpu: [x64] - os: [win32] - - '@sec-ant/readable-stream@0.4.1': - resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - - '@sindresorhus/merge-streams@4.0.0': - resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} - engines: {node: '>=18'} - - '@tsconfig/node22@22.0.2': - resolution: {integrity: sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/node@22.18.3': - resolution: {integrity: sha512-gTVM8js2twdtqM+AE2PdGEe9zGQY4UvmFjan9rZcVb6FGdStfjWoWejdmy4CfWVO9rh5MiYQGZloKAGkJt8lMw==} - - '@vitejs/plugin-vue@6.0.1': - resolution: {integrity: sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - vue: ^3.2.25 - - '@volar/language-core@2.4.23': - resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==} - - '@volar/source-map@2.4.23': - resolution: {integrity: sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==} - - '@volar/typescript@2.4.23': - resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==} - - '@vue/babel-helper-vue-transform-on@1.5.0': - resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} - - '@vue/babel-plugin-jsx@1.5.0': - resolution: {integrity: sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - peerDependenciesMeta: - '@babel/core': - optional: true - - '@vue/babel-plugin-resolve-type@1.5.0': - resolution: {integrity: sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@vue/compiler-core@3.5.21': - resolution: {integrity: sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==} - - '@vue/compiler-dom@3.5.21': - resolution: {integrity: sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==} - - '@vue/compiler-sfc@3.5.21': - resolution: {integrity: sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==} - - '@vue/compiler-ssr@3.5.21': - resolution: {integrity: sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==} - - '@vue/compiler-vue2@2.7.16': - resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} - - '@vue/devtools-api@6.6.4': - resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - - '@vue/devtools-core@8.0.2': - resolution: {integrity: sha512-V7eKTTHoS6KfK8PSGMLZMhGv/9yNDrmv6Qc3r71QILulnzPnqK2frsTyx3e2MrhdUZnENPEm6hcb4z0GZOqNhw==} - peerDependencies: - vue: ^3.0.0 - - '@vue/devtools-kit@8.0.2': - resolution: {integrity: sha512-yjZKdEmhJzQqbOh4KFBfTOQjDPMrjjBNCnHBvnTGJX+YLAqoUtY2J+cg7BE+EA8KUv8LprECq04ts75wCoIGWA==} - - '@vue/devtools-shared@8.0.2': - resolution: {integrity: sha512-mLU0QVdy5Lp40PMGSixDw/Kbd6v5dkQXltd2r+mdVQV7iUog2NlZuLxFZApFZ/mObUBDhoCpf0T3zF2FWWdeHw==} - - '@vue/language-core@3.0.7': - resolution: {integrity: sha512-0sqqyqJ0Gn33JH3TdIsZLCZZ8Gr4kwlg8iYOnOrDDkJKSjFurlQY/bEFQx5zs7SX2C/bjMkmPYq/NiyY1fTOkw==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@vue/reactivity@3.5.21': - resolution: {integrity: sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==} - - '@vue/runtime-core@3.5.21': - resolution: {integrity: sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==} - - '@vue/runtime-dom@3.5.21': - resolution: {integrity: sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==} - - '@vue/server-renderer@3.5.21': - resolution: {integrity: sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==} - peerDependencies: - vue: 3.5.21 - - '@vue/shared@3.5.21': - resolution: {integrity: sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==} - - '@vue/tsconfig@0.7.0': - resolution: {integrity: sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==} - peerDependencies: - typescript: 5.x - vue: ^3.4.0 - peerDependenciesMeta: - typescript: - optional: true - vue: - optional: true - - alien-signals@2.0.7: - resolution: {integrity: sha512-wE7y3jmYeb0+h6mr5BOovuqhFv22O/MV9j5p0ndJsa7z1zJNPGQ4ph5pQk/kTTCWRC3xsA4SmtwmkzQO+7NCNg==} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - - ansis@4.1.0: - resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} - engines: {node: '>=14'} - - baseline-browser-mapping@2.8.4: - resolution: {integrity: sha512-L+YvJwGAgwJBV1p6ffpSTa2KRc69EeeYGYjRVWKs0GKrK+LON0GC0gV+rKSNtALEDvMDqkvCFq9r1r94/Gjwxw==} - hasBin: true - - birpc@2.5.0: - resolution: {integrity: sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==} - - browserslist@4.26.0: - resolution: {integrity: sha512-P9go2WrP9FiPwLv3zqRD/Uoxo0RSHjzFCiQz7d4vbmwNqQFo9T9WCeP/Qn5EbcKQY6DBbkxEXNcpJOmncNrb7A==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - bundle-name@4.1.0: - resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} - engines: {node: '>=18'} - - caniuse-lite@1.0.30001741: - resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - - de-indent@1.0.2: - resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - default-browser-id@5.0.0: - resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} - engines: {node: '>=18'} - - default-browser@5.2.1: - resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} - engines: {node: '>=18'} - - define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} - - electron-to-chromium@1.5.218: - resolution: {integrity: sha512-uwwdN0TUHs8u6iRgN8vKeWZMRll4gBkz+QMqdS7DDe49uiK68/UX92lFb61oiFPrpYZNeZIqa4bA7O6Aiasnzg==} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - error-stack-parser-es@1.0.5: - resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} - - esbuild@0.25.9: - resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - execa@9.6.0: - resolution: {integrity: sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==} - engines: {node: ^18.19.0 || >=20.5.0} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - figures@6.1.0: - resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} - engines: {node: '>=18'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-stream@9.0.1: - resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} - engines: {node: '>=18'} - - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - - hookable@5.5.3: - resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} - - human-signals@8.0.1: - resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} - engines: {node: '>=18.18.0'} - - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - - is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - - is-stream@4.0.1: - resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} - engines: {node: '>=18'} - - is-unicode-supported@2.1.0: - resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} - engines: {node: '>=18'} - - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} - - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} - engines: {node: '>=16'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - isexe@3.1.1: - resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} - engines: {node: '>=16'} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-parse-even-better-errors@4.0.0: - resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} - engines: {node: ^18.17.0 || >=20.5.0} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - kolorist@1.8.0: - resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - magic-string@0.30.19: - resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} - - memorystream@0.3.1: - resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} - engines: {node: '>= 0.10.0'} - - mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - - mrmime@2.0.1: - resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} - engines: {node: '>=10'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - muggle-string@0.4.1: - resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - nanoid@5.1.5: - resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} - engines: {node: ^18 || >=20} - hasBin: true - - node-releases@2.0.21: - resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==} - - npm-normalize-package-bin@4.0.0: - resolution: {integrity: sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==} - engines: {node: ^18.17.0 || >=20.5.0} - - npm-run-all2@8.0.4: - resolution: {integrity: sha512-wdbB5My48XKp2ZfJUlhnLVihzeuA1hgBnqB2J9ahV77wLS+/YAJAlN8I+X3DIFIPZ3m5L7nplmlbhNiFDmXRDA==} - engines: {node: ^20.5.0 || >=22.0.0, npm: '>= 10'} - hasBin: true - - npm-run-path@6.0.0: - resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} - engines: {node: '>=18'} - - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - - open@10.2.0: - resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} - engines: {node: '>=18'} - - parse-ms@4.0.0: - resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} - engines: {node: '>=18'} - - path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - perfect-debounce@2.0.0: - resolution: {integrity: sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - pidtree@0.6.0: - resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} - engines: {node: '>=0.10'} - hasBin: true - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - pretty-ms@9.3.0: - resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} - engines: {node: '>=18'} - - read-package-json-fast@4.0.0: - resolution: {integrity: sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==} - engines: {node: ^18.17.0 || >=20.5.0} - - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - - rollup@4.50.2: - resolution: {integrity: sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - run-applescript@7.1.0: - resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} - engines: {node: '>=18'} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - sirv@3.0.2: - resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} - engines: {node: '>=18'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - speakingurl@14.0.1: - resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} - engines: {node: '>=0.10.0'} - - strip-final-newline@4.0.0: - resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} - engines: {node: '>=18'} - - superjson@2.2.2: - resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} - engines: {node: '>=16'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - totalist@3.0.1: - resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} - engines: {node: '>=6'} - - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - unicorn-magic@0.3.0: - resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} - engines: {node: '>=18'} - - unplugin-utils@0.3.0: - resolution: {integrity: sha512-JLoggz+PvLVMJo+jZt97hdIIIZ2yTzGgft9e9q8iMrC4ewufl62ekeW7mixBghonn2gVb/ICjyvlmOCUBnJLQg==} - engines: {node: '>=20.19.0'} - - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - vite-dev-rpc@1.1.0: - resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} - peerDependencies: - vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 - - vite-hot-client@2.1.0: - resolution: {integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==} - peerDependencies: - vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 - - vite-plugin-inspect@11.3.3: - resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} - engines: {node: '>=14'} - peerDependencies: - '@nuxt/kit': '*' - vite: ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - '@nuxt/kit': - optional: true - - vite-plugin-vue-devtools@8.0.2: - resolution: {integrity: sha512-1069qvMBcyAu3yXQlvYrkwoyLOk0lSSR/gTKy/vy+Det7TXnouGei6ZcKwr5TIe938v/14oLlp0ow6FSJkkORA==} - engines: {node: '>=v14.21.3'} - peerDependencies: - vite: ^6.0.0 || ^7.0.0-0 - - vite-plugin-vue-inspector@5.3.2: - resolution: {integrity: sha512-YvEKooQcSiBTAs0DoYLfefNja9bLgkFM7NI2b07bE2SruuvX0MEa9cMaxjKVMkeCp5Nz9FRIdcN1rOdFVBeL6Q==} - peerDependencies: - vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 - - vite@7.1.11: - resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vscode-uri@3.1.0: - resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} - - vue-router@4.5.1: - resolution: {integrity: sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==} - peerDependencies: - vue: ^3.2.0 - - vue-tsc@3.0.7: - resolution: {integrity: sha512-BSMmW8GGEgHykrv7mRk6zfTdK+tw4MBZY/x6fFa7IkdXK3s/8hQRacPjG9/8YKFDIWGhBocwi6PlkQQ/93OgIQ==} - hasBin: true - peerDependencies: - typescript: '>=5.0.0' - - vue@3.5.21: - resolution: {integrity: sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - which@5.0.0: - resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - - wsl-utils@0.1.0: - resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} - engines: {node: '>=18'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yoctocolors@2.1.2: - resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} - engines: {node: '>=18'} - -snapshots: - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.4': {} - - '@babel/core@7.28.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.3': - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.28.4 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.4 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.0 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.4 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-member-expression-to-functions@7.27.1': - dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.28.4 - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.27.1': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.4': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - - '@babel/parser@7.28.4': - dependencies: - '@babel/types': 7.28.4 - - '@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-decorators': 7.27.1(@babel/core@7.28.4) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-syntax-decorators@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-typescript@7.28.0(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) - transitivePeerDependencies: - - supports-color - - '@babel/template@7.27.2': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - - '@babel/traverse@7.28.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.28.4': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - - '@esbuild/aix-ppc64@0.25.9': - optional: true - - '@esbuild/android-arm64@0.25.9': - optional: true - - '@esbuild/android-arm@0.25.9': - optional: true - - '@esbuild/android-x64@0.25.9': - optional: true - - '@esbuild/darwin-arm64@0.25.9': - optional: true - - '@esbuild/darwin-x64@0.25.9': - optional: true - - '@esbuild/freebsd-arm64@0.25.9': - optional: true - - '@esbuild/freebsd-x64@0.25.9': - optional: true - - '@esbuild/linux-arm64@0.25.9': - optional: true - - '@esbuild/linux-arm@0.25.9': - optional: true - - '@esbuild/linux-ia32@0.25.9': - optional: true - - '@esbuild/linux-loong64@0.25.9': - optional: true - - '@esbuild/linux-mips64el@0.25.9': - optional: true - - '@esbuild/linux-ppc64@0.25.9': - optional: true - - '@esbuild/linux-riscv64@0.25.9': - optional: true - - '@esbuild/linux-s390x@0.25.9': - optional: true - - '@esbuild/linux-x64@0.25.9': - optional: true - - '@esbuild/netbsd-arm64@0.25.9': - optional: true - - '@esbuild/netbsd-x64@0.25.9': - optional: true - - '@esbuild/openbsd-arm64@0.25.9': - optional: true - - '@esbuild/openbsd-x64@0.25.9': - optional: true - - '@esbuild/openharmony-arm64@0.25.9': - optional: true - - '@esbuild/sunos-x64@0.25.9': - optional: true - - '@esbuild/win32-arm64@0.25.9': - optional: true - - '@esbuild/win32-ia32@0.25.9': - optional: true - - '@esbuild/win32-x64@0.25.9': - optional: true - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@polka/url@1.0.0-next.29': {} - - '@rolldown/pluginutils@1.0.0-beta.29': {} - - '@rollup/rollup-android-arm-eabi@4.50.2': - optional: true - - '@rollup/rollup-android-arm64@4.50.2': - optional: true - - '@rollup/rollup-darwin-arm64@4.50.2': - optional: true - - '@rollup/rollup-darwin-x64@4.50.2': - optional: true - - '@rollup/rollup-freebsd-arm64@4.50.2': - optional: true - - '@rollup/rollup-freebsd-x64@4.50.2': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.50.2': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.50.2': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.50.2': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.50.2': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.50.2': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.50.2': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.50.2': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.50.2': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.50.2': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.50.2': - optional: true - - '@rollup/rollup-linux-x64-musl@4.50.2': - optional: true - - '@rollup/rollup-openharmony-arm64@4.50.2': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.50.2': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.50.2': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.50.2': - optional: true - - '@sec-ant/readable-stream@0.4.1': {} - - '@sindresorhus/merge-streams@4.0.0': {} - - '@tsconfig/node22@22.0.2': {} - - '@types/estree@1.0.8': {} - - '@types/node@22.18.3': - dependencies: - undici-types: 6.21.0 - - '@vitejs/plugin-vue@6.0.1(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))': - dependencies: - '@rolldown/pluginutils': 1.0.0-beta.29 - vite: 7.1.11(@types/node@22.18.3) - vue: 3.5.21(typescript@5.8.3) - - '@volar/language-core@2.4.23': - dependencies: - '@volar/source-map': 2.4.23 - - '@volar/source-map@2.4.23': {} - - '@volar/typescript@2.4.23': - dependencies: - '@volar/language-core': 2.4.23 - path-browserify: 1.0.1 - vscode-uri: 3.1.0 - - '@vue/babel-helper-vue-transform-on@1.5.0': {} - - '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.4)': - dependencies: - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - '@vue/babel-helper-vue-transform-on': 1.5.0 - '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.28.4) - '@vue/shared': 3.5.21 - optionalDependencies: - '@babel/core': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.28.4)': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/core': 7.28.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/parser': 7.28.4 - '@vue/compiler-sfc': 3.5.21 - transitivePeerDependencies: - - supports-color - - '@vue/compiler-core@3.5.21': - dependencies: - '@babel/parser': 7.28.4 - '@vue/shared': 3.5.21 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - - '@vue/compiler-dom@3.5.21': - dependencies: - '@vue/compiler-core': 3.5.21 - '@vue/shared': 3.5.21 - - '@vue/compiler-sfc@3.5.21': - dependencies: - '@babel/parser': 7.28.4 - '@vue/compiler-core': 3.5.21 - '@vue/compiler-dom': 3.5.21 - '@vue/compiler-ssr': 3.5.21 - '@vue/shared': 3.5.21 - estree-walker: 2.0.2 - magic-string: 0.30.19 - postcss: 8.5.6 - source-map-js: 1.2.1 - - '@vue/compiler-ssr@3.5.21': - dependencies: - '@vue/compiler-dom': 3.5.21 - '@vue/shared': 3.5.21 - - '@vue/compiler-vue2@2.7.16': - dependencies: - de-indent: 1.0.2 - he: 1.2.0 - - '@vue/devtools-api@6.6.4': {} - - '@vue/devtools-core@8.0.2(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))': - dependencies: - '@vue/devtools-kit': 8.0.2 - '@vue/devtools-shared': 8.0.2 - mitt: 3.0.1 - nanoid: 5.1.5 - pathe: 2.0.3 - vite-hot-client: 2.1.0(vite@7.1.11(@types/node@22.18.3)) - vue: 3.5.21(typescript@5.8.3) - transitivePeerDependencies: - - vite - - '@vue/devtools-kit@8.0.2': - dependencies: - '@vue/devtools-shared': 8.0.2 - birpc: 2.5.0 - hookable: 5.5.3 - mitt: 3.0.1 - perfect-debounce: 2.0.0 - speakingurl: 14.0.1 - superjson: 2.2.2 - - '@vue/devtools-shared@8.0.2': - dependencies: - rfdc: 1.4.1 - - '@vue/language-core@3.0.7(typescript@5.8.3)': - dependencies: - '@volar/language-core': 2.4.23 - '@vue/compiler-dom': 3.5.21 - '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.21 - alien-signals: 2.0.7 - muggle-string: 0.4.1 - path-browserify: 1.0.1 - picomatch: 4.0.3 - optionalDependencies: - typescript: 5.8.3 - - '@vue/reactivity@3.5.21': - dependencies: - '@vue/shared': 3.5.21 - - '@vue/runtime-core@3.5.21': - dependencies: - '@vue/reactivity': 3.5.21 - '@vue/shared': 3.5.21 - - '@vue/runtime-dom@3.5.21': - dependencies: - '@vue/reactivity': 3.5.21 - '@vue/runtime-core': 3.5.21 - '@vue/shared': 3.5.21 - csstype: 3.1.3 - - '@vue/server-renderer@3.5.21(vue@3.5.21(typescript@5.8.3))': - dependencies: - '@vue/compiler-ssr': 3.5.21 - '@vue/shared': 3.5.21 - vue: 3.5.21(typescript@5.8.3) - - '@vue/shared@3.5.21': {} - - '@vue/tsconfig@0.7.0(typescript@5.8.3)(vue@3.5.21(typescript@5.8.3))': - optionalDependencies: - typescript: 5.8.3 - vue: 3.5.21(typescript@5.8.3) - - alien-signals@2.0.7: {} - - ansi-styles@6.2.3: {} - - ansis@4.1.0: {} - - baseline-browser-mapping@2.8.4: {} - - birpc@2.5.0: {} - - browserslist@4.26.0: - dependencies: - baseline-browser-mapping: 2.8.4 - caniuse-lite: 1.0.30001741 - electron-to-chromium: 1.5.218 - node-releases: 2.0.21 - update-browserslist-db: 1.1.3(browserslist@4.26.0) - - bundle-name@4.1.0: - dependencies: - run-applescript: 7.1.0 - - caniuse-lite@1.0.30001741: {} - - convert-source-map@2.0.0: {} - - copy-anything@3.0.5: - dependencies: - is-what: 4.1.16 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - csstype@3.1.3: {} - - de-indent@1.0.2: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - default-browser-id@5.0.0: {} - - default-browser@5.2.1: - dependencies: - bundle-name: 4.1.0 - default-browser-id: 5.0.0 - - define-lazy-prop@3.0.0: {} - - electron-to-chromium@1.5.218: {} - - entities@4.5.0: {} - - error-stack-parser-es@1.0.5: {} - - esbuild@0.25.9: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.9 - '@esbuild/android-arm': 0.25.9 - '@esbuild/android-arm64': 0.25.9 - '@esbuild/android-x64': 0.25.9 - '@esbuild/darwin-arm64': 0.25.9 - '@esbuild/darwin-x64': 0.25.9 - '@esbuild/freebsd-arm64': 0.25.9 - '@esbuild/freebsd-x64': 0.25.9 - '@esbuild/linux-arm': 0.25.9 - '@esbuild/linux-arm64': 0.25.9 - '@esbuild/linux-ia32': 0.25.9 - '@esbuild/linux-loong64': 0.25.9 - '@esbuild/linux-mips64el': 0.25.9 - '@esbuild/linux-ppc64': 0.25.9 - '@esbuild/linux-riscv64': 0.25.9 - '@esbuild/linux-s390x': 0.25.9 - '@esbuild/linux-x64': 0.25.9 - '@esbuild/netbsd-arm64': 0.25.9 - '@esbuild/netbsd-x64': 0.25.9 - '@esbuild/openbsd-arm64': 0.25.9 - '@esbuild/openbsd-x64': 0.25.9 - '@esbuild/openharmony-arm64': 0.25.9 - '@esbuild/sunos-x64': 0.25.9 - '@esbuild/win32-arm64': 0.25.9 - '@esbuild/win32-ia32': 0.25.9 - '@esbuild/win32-x64': 0.25.9 - - escalade@3.2.0: {} - - estree-walker@2.0.2: {} - - execa@9.6.0: - dependencies: - '@sindresorhus/merge-streams': 4.0.0 - cross-spawn: 7.0.6 - figures: 6.1.0 - get-stream: 9.0.1 - human-signals: 8.0.1 - is-plain-obj: 4.1.0 - is-stream: 4.0.1 - npm-run-path: 6.0.0 - pretty-ms: 9.3.0 - signal-exit: 4.1.0 - strip-final-newline: 4.0.0 - yoctocolors: 2.1.2 - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - figures@6.1.0: - dependencies: - is-unicode-supported: 2.1.0 - - fsevents@2.3.3: - optional: true - - gensync@1.0.0-beta.2: {} - - get-stream@9.0.1: - dependencies: - '@sec-ant/readable-stream': 0.4.1 - is-stream: 4.0.1 - - he@1.2.0: {} - - hookable@5.5.3: {} - - human-signals@8.0.1: {} - - is-docker@3.0.0: {} - - is-inside-container@1.0.0: - dependencies: - is-docker: 3.0.0 - - is-plain-obj@4.1.0: {} - - is-stream@4.0.1: {} - - is-unicode-supported@2.1.0: {} - - is-what@4.1.16: {} - - is-wsl@3.1.0: - dependencies: - is-inside-container: 1.0.0 - - isexe@2.0.0: {} - - isexe@3.1.1: {} - - js-tokens@4.0.0: {} - - jsesc@3.1.0: {} - - json-parse-even-better-errors@4.0.0: {} - - json5@2.2.3: {} - - kolorist@1.8.0: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - magic-string@0.30.19: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - memorystream@0.3.1: {} - - mitt@3.0.1: {} - - mrmime@2.0.1: {} - - ms@2.1.3: {} - - muggle-string@0.4.1: {} - - nanoid@3.3.11: {} - - nanoid@5.1.5: {} - - node-releases@2.0.21: {} - - npm-normalize-package-bin@4.0.0: {} - - npm-run-all2@8.0.4: - dependencies: - ansi-styles: 6.2.3 - cross-spawn: 7.0.6 - memorystream: 0.3.1 - picomatch: 4.0.3 - pidtree: 0.6.0 - read-package-json-fast: 4.0.0 - shell-quote: 1.8.3 - which: 5.0.0 - - npm-run-path@6.0.0: - dependencies: - path-key: 4.0.0 - unicorn-magic: 0.3.0 - - ohash@2.0.11: {} - - open@10.2.0: - dependencies: - default-browser: 5.2.1 - define-lazy-prop: 3.0.0 - is-inside-container: 1.0.0 - wsl-utils: 0.1.0 - - parse-ms@4.0.0: {} - - path-browserify@1.0.1: {} - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - pathe@2.0.3: {} - - perfect-debounce@2.0.0: {} - - picocolors@1.1.1: {} - - picomatch@4.0.3: {} - - pidtree@0.6.0: {} - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - pretty-ms@9.3.0: - dependencies: - parse-ms: 4.0.0 - - read-package-json-fast@4.0.0: - dependencies: - json-parse-even-better-errors: 4.0.0 - npm-normalize-package-bin: 4.0.0 - - rfdc@1.4.1: {} - - rollup@4.50.2: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.50.2 - '@rollup/rollup-android-arm64': 4.50.2 - '@rollup/rollup-darwin-arm64': 4.50.2 - '@rollup/rollup-darwin-x64': 4.50.2 - '@rollup/rollup-freebsd-arm64': 4.50.2 - '@rollup/rollup-freebsd-x64': 4.50.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.50.2 - '@rollup/rollup-linux-arm-musleabihf': 4.50.2 - '@rollup/rollup-linux-arm64-gnu': 4.50.2 - '@rollup/rollup-linux-arm64-musl': 4.50.2 - '@rollup/rollup-linux-loong64-gnu': 4.50.2 - '@rollup/rollup-linux-ppc64-gnu': 4.50.2 - '@rollup/rollup-linux-riscv64-gnu': 4.50.2 - '@rollup/rollup-linux-riscv64-musl': 4.50.2 - '@rollup/rollup-linux-s390x-gnu': 4.50.2 - '@rollup/rollup-linux-x64-gnu': 4.50.2 - '@rollup/rollup-linux-x64-musl': 4.50.2 - '@rollup/rollup-openharmony-arm64': 4.50.2 - '@rollup/rollup-win32-arm64-msvc': 4.50.2 - '@rollup/rollup-win32-ia32-msvc': 4.50.2 - '@rollup/rollup-win32-x64-msvc': 4.50.2 - fsevents: 2.3.3 - - run-applescript@7.1.0: {} - - semver@6.3.1: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - shell-quote@1.8.3: {} - - signal-exit@4.1.0: {} - - sirv@3.0.2: - dependencies: - '@polka/url': 1.0.0-next.29 - mrmime: 2.0.1 - totalist: 3.0.1 - - source-map-js@1.2.1: {} - - speakingurl@14.0.1: {} - - strip-final-newline@4.0.0: {} - - superjson@2.2.2: - dependencies: - copy-anything: 3.0.5 - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - totalist@3.0.1: {} - - typescript@5.8.3: {} - - undici-types@6.21.0: {} - - unicorn-magic@0.3.0: {} - - unplugin-utils@0.3.0: - dependencies: - pathe: 2.0.3 - picomatch: 4.0.3 - - update-browserslist-db@1.1.3(browserslist@4.26.0): - dependencies: - browserslist: 4.26.0 - escalade: 3.2.0 - picocolors: 1.1.1 - - vite-dev-rpc@1.1.0(vite@7.1.11(@types/node@22.18.3)): - dependencies: - birpc: 2.5.0 - vite: 7.1.11(@types/node@22.18.3) - vite-hot-client: 2.1.0(vite@7.1.11(@types/node@22.18.3)) - - vite-hot-client@2.1.0(vite@7.1.11(@types/node@22.18.3)): - dependencies: - vite: 7.1.11(@types/node@22.18.3) - - vite-plugin-inspect@11.3.3(vite@7.1.11(@types/node@22.18.3)): - dependencies: - ansis: 4.1.0 - debug: 4.4.3 - error-stack-parser-es: 1.0.5 - ohash: 2.0.11 - open: 10.2.0 - perfect-debounce: 2.0.0 - sirv: 3.0.2 - unplugin-utils: 0.3.0 - vite: 7.1.11(@types/node@22.18.3) - vite-dev-rpc: 1.1.0(vite@7.1.11(@types/node@22.18.3)) - transitivePeerDependencies: - - supports-color - - vite-plugin-vue-devtools@8.0.2(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3)): - dependencies: - '@vue/devtools-core': 8.0.2(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3)) - '@vue/devtools-kit': 8.0.2 - '@vue/devtools-shared': 8.0.2 - execa: 9.6.0 - sirv: 3.0.2 - vite: 7.1.11(@types/node@22.18.3) - vite-plugin-inspect: 11.3.3(vite@7.1.11(@types/node@22.18.3)) - vite-plugin-vue-inspector: 5.3.2(vite@7.1.11(@types/node@22.18.3)) - transitivePeerDependencies: - - '@nuxt/kit' - - supports-color - - vue - - vite-plugin-vue-inspector@5.3.2(vite@7.1.11(@types/node@22.18.3)): - dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.4) - '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.4) - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.4) - '@vue/compiler-dom': 3.5.21 - kolorist: 1.8.0 - magic-string: 0.30.19 - vite: 7.1.11(@types/node@22.18.3) - transitivePeerDependencies: - - supports-color - - vite@7.1.11(@types/node@22.18.3): - dependencies: - esbuild: 0.25.9 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.50.2 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 22.18.3 - fsevents: 2.3.3 - - vscode-uri@3.1.0: {} - - vue-router@4.5.1(vue@3.5.21(typescript@5.8.3)): - dependencies: - '@vue/devtools-api': 6.6.4 - vue: 3.5.21(typescript@5.8.3) - - vue-tsc@3.0.7(typescript@5.8.3): - dependencies: - '@volar/typescript': 2.4.23 - '@vue/language-core': 3.0.7(typescript@5.8.3) - typescript: 5.8.3 - - vue@3.5.21(typescript@5.8.3): - dependencies: - '@vue/compiler-dom': 3.5.21 - '@vue/compiler-sfc': 3.5.21 - '@vue/runtime-dom': 3.5.21 - '@vue/server-renderer': 3.5.21(vue@3.5.21(typescript@5.8.3)) - '@vue/shared': 3.5.21 - optionalDependencies: - typescript: 5.8.3 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - which@5.0.0: - dependencies: - isexe: 3.1.1 - - wsl-utils@0.1.0: - dependencies: - is-wsl: 3.1.0 - - yallist@3.1.1: {} - - yoctocolors@2.1.2: {} diff --git a/examples/tutorials/nhost-vue-tutorial/public/favicon.ico b/examples/tutorials/nhost-vue-tutorial/public/favicon.ico deleted file mode 100644 index df36fcfb7..000000000 Binary files a/examples/tutorials/nhost-vue-tutorial/public/favicon.ico and /dev/null differ diff --git a/examples/tutorials/nhost-vue-tutorial/src/App.vue b/examples/tutorials/nhost-vue-tutorial/src/App.vue deleted file mode 100644 index 407ba5c82..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/App.vue +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/assets/base.css b/examples/tutorials/nhost-vue-tutorial/src/assets/base.css deleted file mode 100644 index a675d59cf..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/assets/base.css +++ /dev/null @@ -1,76 +0,0 @@ -/* color palette from */ -:root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} - -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background: var(--vt-c-black); - --color-background-soft: var(--vt-c-black-soft); - --color-background-mute: var(--vt-c-black-mute); - - --color-border: var(--vt-c-divider-dark-2); - --color-border-hover: var(--vt-c-divider-dark-1); - - --color-heading: var(--vt-c-text-dark-1); - --color-text: var(--vt-c-text-dark-2); - } -} - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - font-weight: normal; -} - -body { - min-height: 100vh; - color: var(--color-text); - background: var(--color-background); - transition: - color 0.5s, - background-color 0.5s; - line-height: 1.6; - font-family: - Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, - Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - font-size: 15px; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/examples/tutorials/nhost-vue-tutorial/src/assets/logo.svg b/examples/tutorials/nhost-vue-tutorial/src/assets/logo.svg deleted file mode 100644 index 756566035..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/tutorials/nhost-vue-tutorial/src/assets/main.css b/examples/tutorials/nhost-vue-tutorial/src/assets/main.css deleted file mode 100644 index 1b327bc66..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/assets/main.css +++ /dev/null @@ -1,864 +0,0 @@ -:root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -#app { - width: 100%; - min-height: 100vh; - display: block; - margin: 0; - padding: 0; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} - -a:hover { - color: #535bf2; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} - -button:hover { - border-color: #646cff; -} - -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -input, -textarea { - width: 100%; - padding: 0.875rem 1rem; - border: 1px solid rgba(255, 255, 255, 0.2); - border-radius: 8px; - font-size: 0.875rem; - transition: all 0.2s ease; - background: rgba(255, 255, 255, 0.05); - color: white; - box-sizing: border-box; - font-family: inherit; -} - -input:focus, -textarea:focus { - outline: none; - border-color: #3b82f6; - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); - background: rgba(255, 255, 255, 0.08); -} - -input::placeholder, -textarea::placeholder { - color: rgba(255, 255, 255, 0.5); -} - -textarea { - resize: vertical; - min-height: 4rem; -} - -label { - display: block; - margin: 0 0 0.5rem 0; - font-weight: 500; - color: rgba(255, 255, 255, 0.9); - font-size: 0.875rem; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -/* Global Layout */ -.app-content { - padding: 0 2rem 2rem; - max-width: 800px; - margin: 0 auto; -} - -.page-center { - text-align: center; - padding: 2rem; -} - -.page-header { - margin-bottom: 2rem; -} - -.page-title { - font-weight: 700; - margin: 0; - display: flex; - align-items: center; - gap: 1rem; -} - -.margin-bottom { - margin-bottom: 1rem; -} - -.margin-top { - margin-top: 1rem; -} - -.container { - width: 800px; - max-width: calc(100vw - 4rem); - min-width: 320px; - margin: 0 auto; - padding: 2rem; - box-sizing: border-box; - position: relative; -} - -/* Status Messages */ -.success-message { - padding: 1rem; - background-color: #d4edda; - color: #155724; - border-radius: 8px; - margin-bottom: 1rem; -} - -.error-message { - background: rgba(239, 68, 68, 0.1); - color: #ef4444; - border: 1px solid rgba(239, 68, 68, 0.3); - border-radius: 12px; - padding: 1rem 1.5rem; - margin: 1rem 0; -} - -.help-text { - color: #666; -} - -.verification-status { - color: #28a745; - font-size: 1.2rem; - font-weight: bold; - margin-bottom: 1rem; -} - -.verification-status.error { - color: #dc3545; - font-size: 1.1rem; -} - -/* Email Verification Status */ -.email-verified { - color: #10b981; - font-weight: bold; - margin-left: 0.5rem; -} - -.email-unverified { - color: #ef4444; - font-weight: bold; - margin-left: 0.5rem; -} - -/* Debug Info */ -.debug-panel { - margin-bottom: 1rem; - padding: 1rem; - background-color: #f8f9fa; - border-radius: 8px; - text-align: left; - max-height: 200px; - overflow: auto; -} - -.debug-title { - font-weight: bold; - margin-bottom: 0.5rem; -} - -.debug-item { - margin-bottom: 0.25rem; -} - -.debug-key { - font-family: monospace; - color: #007bff; -} - -.debug-value { - font-family: monospace; -} - -/* Session Display */ -.session-display { - font-size: 0.75rem; - overflow: auto; - margin: 0; - line-height: 1.4; - white-space: pre-wrap; - word-break: break-word; -} - -/* Loading Spinner */ -.spinner-verify { - width: 32px; - height: 32px; - border: 3px solid #f3f3f3; - border-top: 3px solid #007bff; - border-radius: 50%; - animation: spin 1s linear infinite; - margin: 0 auto; -} - -/* Navigation */ -.navigation { - background: rgba(255, 255, 255, 0.05); - backdrop-filter: blur(10px); - border-bottom: 1px solid rgba(255, 255, 255, 0.1); - position: sticky; - top: 0; - z-index: 100; - margin-bottom: 2rem; -} - -.nav-container { - max-width: 800px; - margin: 0 auto; - padding: 1rem 2rem; - display: flex; - justify-content: space-between; - align-items: center; -} - -.nav-logo { - font-size: 1.25rem; - font-weight: 700; - color: white; - text-decoration: none; - background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.nav-logo:hover { - opacity: 0.8; -} - -.nav-links { - display: flex; - align-items: center; - gap: 1.5rem; -} - -.nav-link { - color: rgba(255, 255, 255, 0.8); - text-decoration: none; - font-weight: 500; - font-size: 0.875rem; - padding: 0.5rem 0.75rem; - border-radius: 6px; - transition: all 0.2s ease; - border: none; - background: none; - cursor: pointer; - font-family: inherit; -} - -.nav-link:hover { - color: white; - background: rgba(255, 255, 255, 0.1); -} - -.nav-button { - color: #ef4444; -} - -.nav-button:hover { - background: rgba(239, 68, 68, 0.2); -} - -/* Buttons */ -.btn { - padding: 0.75rem 1.5rem; - border: none; - border-radius: 8px; - font-weight: 500; - cursor: pointer; - transition: all 0.2s ease; - font-size: 0.875rem; - display: inline-flex; - align-items: center; - justify-content: center; - gap: 0.5rem; - min-width: 120px; -} - -.btn-primary { - background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%); - color: white; -} - -.btn-primary:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4); -} - -.btn-secondary { - background: rgba(255, 255, 255, 0.1); - color: white; - border: 1px solid rgba(255, 255, 255, 0.2); -} - -.btn-secondary:hover { - background: rgba(255, 255, 255, 0.2); -} - -.btn-cancel { - background: rgba(239, 68, 68, 0.1); - color: #ef4444; - border: 1px solid rgba(239, 68, 68, 0.3); -} - -.btn-cancel:hover { - background: rgba(239, 68, 68, 0.2); -} - -/* Loading State */ -.loading-container { - display: flex; - justify-content: center; - align-items: center; - padding: 4rem 2rem; -} - -.loading-content { - display: flex; - align-items: center; - gap: 1rem; -} - -.spinner { - width: 2rem; - height: 2rem; - border: 3px solid rgba(59, 130, 246, 0.3); - border-top: 3px solid #3b82f6; - border-radius: 50%; - animation: spin 1s linear infinite; -} - -.loading-text { - color: rgba(255, 255, 255, 0.7); - font-size: 0.875rem; -} - -/* Empty State */ -.empty-state { - text-align: center; - padding: 4rem 2rem; - background: rgba(255, 255, 255, 0.02); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 16px; -} - -.empty-icon { - width: 4rem; - height: 4rem; - color: rgba(255, 255, 255, 0.4); - margin: 0 auto 1rem; -} - -.empty-title { - font-size: 1.25rem; - font-weight: 600; - color: white; - margin: 0 0 0.5rem 0; -} - -.empty-description { - color: rgba(255, 255, 255, 0.6); - margin: 0; -} - -/* Forms */ -.form-card { - background: rgba(255, 255, 255, 0.05); - backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 16px; - padding: 2rem; - margin-bottom: 2rem; - width: 100%; - box-sizing: border-box; -} - -.form-title { - font-size: 1.5rem; - font-weight: 600; - color: white; - margin: 0 0 1.5rem 0; -} - -.form-fields { - display: flex; - flex-direction: column; - gap: 1.5rem; -} - -.field-group { - display: flex; - flex-direction: column; -} - -.form-actions { - display: flex; - gap: 1rem; - margin-top: 1rem; -} - -/* Auth Pages */ -.auth-form { - max-width: 400px; -} - -.auth-form-field { - margin-bottom: 1rem; -} - -.auth-input { - width: 100%; - padding: 0.5rem; - margin-top: 0.25rem; -} - -.auth-error { - color: red; - margin-bottom: 1rem; - padding: 0.5rem; - background-color: #fee; - border-radius: 4px; -} - -.auth-button { - width: 100%; - padding: 0.75rem; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; -} - -.auth-button:disabled { - cursor: not-allowed; -} - -.auth-button.primary { - background-color: #28a745; -} - -.auth-button.secondary { - background-color: #007bff; -} - -.auth-links { - margin-top: 1rem; -} - -/* Todos */ - -.todo-form { - width: 100%; -} - -/* Todo List */ -.todos-list { - display: flex; - flex-direction: column; - gap: 1rem; -} - -.todo-card { - background: rgba(255, 255, 255, 0.03); - backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 12px; - transition: all 0.2s ease; - overflow: hidden; - width: 100%; - box-sizing: border-box; -} - -.todo-card:hover { - border-color: rgba(255, 255, 255, 0.2); - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); -} - -.todo-card.completed { - opacity: 0.7; -} - -/* Todo Content */ -.todo-content { - padding: 1rem 1.5rem; -} - -.todo-edit { - padding: 1.5rem; - min-height: 200px; -} - -.edit-fields { - display: flex; - flex-direction: column; - gap: 1rem; -} - -.edit-actions { - display: flex; - gap: 1rem; - margin-top: 1.5rem; -} - -.todo-header { - display: flex; - justify-content: space-between; - align-items: center; - gap: 1rem; -} - -.todo-title-btn { - background: none; - border: none; - padding: 0; - text-align: left; - font-size: 1.25rem; - font-weight: 600; - color: white; - cursor: pointer; - transition: color 0.2s ease; - flex: 1; - line-height: 1.4; - word-wrap: break-word; - overflow-wrap: break-word; - max-width: calc(100% - 140px); -} - -.todo-title-btn:hover { - color: #3b82f6; -} - -.todo-title-btn.completed { - text-decoration: line-through; - color: rgba(255, 255, 255, 0.5); -} - -.todo-actions { - display: flex; - gap: 0.5rem; - flex-shrink: 0; - min-width: 132px; - justify-content: flex-end; -} - -/* Action Buttons */ -.action-btn { - width: 40px; - height: 40px; - border: none; - border-radius: 6px; - cursor: pointer; - background: rgba(255, 255, 255, 0.05); - display: flex; - align-items: center; - justify-content: center; - font-size: 18px; - transition: all 0.2s ease; - -webkit-text-fill-color: currentColor; -} - -.action-btn-complete { - color: #10b981; - font-size: 20px; -} - -.action-btn-complete:hover { - background: rgba(16, 185, 129, 0.2); - color: #34d399; -} - -.action-btn-edit { - color: #3b82f6; -} - -.action-btn-edit:hover { - background: rgba(59, 130, 246, 0.2); - color: #60a5fa; -} - -.action-btn-delete { - color: #ef4444; -} - -.action-btn-delete:hover { - background: rgba(239, 68, 68, 0.2); - color: #f87171; -} - -/* Add Todo Button */ -.add-todo-btn { - width: 36px; - height: 36px; - border: none; - border-radius: 6px; - cursor: pointer; - background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%); - display: flex; - align-items: center; - justify-content: center; - color: white; - font-size: 18px; - font-weight: normal; - -webkit-text-fill-color: white; - transition: all 0.2s ease; -} - -.add-todo-btn:hover { - transform: scale(1.1); - box-shadow: 0 4px 20px rgba(59, 130, 246, 0.4); -} - -/* Todo Details */ -.todo-details { - margin-top: 1rem; - padding-top: 1rem; - border-top: 1px solid rgba(255, 255, 255, 0.1); -} - -.description { - background: rgba(255, 255, 255, 0.02); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 8px; - padding: 1rem; - margin-bottom: 1rem; -} - -.description p { - margin: 0; - color: rgba(255, 255, 255, 0.8); - line-height: 1.6; -} - -.description.completed p { - text-decoration: line-through; - color: rgba(255, 255, 255, 0.5); -} - -.todo-meta { - display: flex; - justify-content: space-between; - align-items: center; - gap: 1rem; -} - -.meta-dates { - display: flex; - gap: 1rem; - flex-wrap: wrap; -} - -.meta-item { - font-size: 0.75rem; - color: rgba(255, 255, 255, 0.5); -} - -.completion-badge { - display: flex; - align-items: center; - gap: 0.25rem; - font-size: 0.75rem; - color: #10b981; - font-weight: 500; -} - -.completion-icon { - width: 0.875rem; - height: 0.875rem; -} - -/* Responsive Design */ -@media (max-width: 768px) { - .nav-container { - padding: 1rem; - flex-direction: column; - gap: 1rem; - } - - .nav-links { - gap: 1rem; - flex-wrap: wrap; - justify-content: center; - } - - .container { - padding: 1rem; - } - - .form-actions { - flex-direction: column; - } - - .edit-actions { - flex-direction: column; - } - - .todo-header { - flex-direction: column; - align-items: flex-start; - gap: 1rem; - } - - .todo-actions { - align-self: stretch; - justify-content: center; - } - - .meta-dates { - flex-direction: column; - gap: 0.25rem; - } - - .todo-meta { - flex-direction: column; - align-items: flex-start; - gap: 0.5rem; - } -} - -/* File Upload */ -.file-upload-btn { - min-height: 120px; - flex-direction: column; - gap: 0.5rem; - width: 100%; - border: 2px dashed rgba(255, 255, 255, 0.3); - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all 0.2s ease; -} - -.file-upload-btn:hover { - border-color: rgba(255, 255, 255, 0.5); - background-color: rgba(255, 255, 255, 0.05); -} - -.file-upload-info { - margin-top: 0.5rem; - font-size: 0.875rem; - color: rgba(255, 255, 255, 0.8); -} - -/* File Table */ -.file-table { - width: 100%; - border-collapse: collapse; -} - -.file-table th { - padding: 0.75rem; - text-align: left; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); - color: rgba(255, 255, 255, 0.7); - font-weight: 500; - font-size: 0.875rem; -} - -.file-table th:last-child { - text-align: center; -} - -.file-table td { - padding: 0.75rem; - border-bottom: 1px solid rgba(255, 255, 255, 0.05); -} - -.file-table tr:hover { - background-color: rgba(255, 255, 255, 0.02); -} - -.file-name { - color: white; - font-weight: 500; -} - -.file-meta { - color: rgba(255, 255, 255, 0.6); - font-size: 0.875rem; -} - -.file-actions { - display: flex; - gap: 0.5rem; - justify-content: center; -} - -/* Responsive File Table */ -@media (max-width: 768px) { - .file-table { - font-size: 0.875rem; - } - - .file-table th, - .file-table td { - padding: 0.5rem; - } - - .file-actions { - flex-direction: column; - gap: 0.25rem; - } -} diff --git a/examples/tutorials/nhost-vue-tutorial/src/components/Navigation.vue b/examples/tutorials/nhost-vue-tutorial/src/components/Navigation.vue deleted file mode 100644 index f22f0486b..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/components/Navigation.vue +++ /dev/null @@ -1,63 +0,0 @@ - - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconCommunity.vue b/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconCommunity.vue deleted file mode 100644 index 2dc8b0552..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconCommunity.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconDocumentation.vue b/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconDocumentation.vue deleted file mode 100644 index 6d4791cfb..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconDocumentation.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconEcosystem.vue b/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconEcosystem.vue deleted file mode 100644 index c3a4f078c..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconEcosystem.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconSupport.vue b/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconSupport.vue deleted file mode 100644 index 7452834d3..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconSupport.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconTooling.vue b/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconTooling.vue deleted file mode 100644 index 660598d7c..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/components/icons/IconTooling.vue +++ /dev/null @@ -1,19 +0,0 @@ - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/lib/nhost/auth.ts b/examples/tutorials/nhost-vue-tutorial/src/lib/nhost/auth.ts deleted file mode 100644 index 1a35aae7d..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/lib/nhost/auth.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { createClient } from "@nhost/nhost-js"; -import type { Session } from "@nhost/nhost-js/auth"; -import { computed, reactive } from "vue"; - -// Global reactive state -const authState = reactive({ - user: null as Session["user"] | null, - session: null as Session | null, - isLoading: true, -}); - -// Create the nhost client -const nhost = createClient({ - region: (import.meta.env["VITE_NHOST_REGION"] as string) || "local", - subdomain: (import.meta.env["VITE_NHOST_SUBDOMAIN"] as string) || "local", -}); - -// Subscription cleanup function -let unsubscribe: (() => void) | null = null; -let lastRefreshTokenIdRef: string | null = null; -let isInitialized = false; - -/** - * Handles session reload when refresh token changes. - * This detects when the session has been updated from other tabs. - * - * @param currentRefreshTokenId - The current refresh token ID to compare against stored value - */ -const reloadSession = (currentRefreshTokenId: string | null) => { - if (currentRefreshTokenId !== lastRefreshTokenIdRef) { - lastRefreshTokenIdRef = currentRefreshTokenId; - - // Update local authentication state to match current session - const currentSession = nhost.getUserSession(); - authState.user = currentSession?.user || null; - authState.session = currentSession; - } -}; - -// Initialize auth state -const initializeAuth = () => { - if (isInitialized) return; - - authState.isLoading = true; - - // Set initial values - const currentSession = nhost.getUserSession(); - authState.user = currentSession?.user || null; - authState.session = currentSession; - lastRefreshTokenIdRef = currentSession?.refreshTokenId ?? null; - authState.isLoading = false; - - // Subscribe to session changes from other browser tabs - // This enables real-time synchronization when user signs in/out in another tab - unsubscribe = nhost.sessionStorage.onChange((currentSession) => { - reloadSession(currentSession?.refreshTokenId ?? null); - }); - - // Handle session changes from page focus events (for additional session consistency) - const checkSessionOnFocus = () => { - reloadSession(nhost.getUserSession()?.refreshTokenId ?? null); - }; - - // Monitor page visibility changes (tab switching, window minimizing) - document.addEventListener("visibilitychange", () => { - if (!document.hidden) { - checkSessionOnFocus(); - } - }); - - // Monitor window focus events (clicking back into the browser window) - window.addEventListener("focus", checkSessionOnFocus); - - isInitialized = true; -}; - -// Cleanup function -const cleanup = () => { - if (unsubscribe) { - unsubscribe(); - unsubscribe = null; - } - isInitialized = false; -}; - -/** - * Vue composable for authentication state and operations. - * - * Provides reactive access to current user session, authentication state, and Nhost client. - * Handles cross-tab session synchronization and automatic state updates. - * - * @returns Object containing reactive authentication state and Nhost client - * - * @example - * ```vue - * - * - * - * ``` - */ -export function useAuth() { - // Initialize auth if not already done - if (!isInitialized && typeof window !== "undefined") { - initializeAuth(); - } - - return { - user: computed(() => authState.user), - session: computed(() => authState.session), - isLoading: computed(() => authState.isLoading), - isAuthenticated: computed(() => !!authState.session), - nhost, - }; -} - -// Initialize auth immediately (for SSR compatibility) -if (typeof window !== "undefined") { - initializeAuth(); -} - -// Cleanup on window unload -if (typeof window !== "undefined") { - window.addEventListener("beforeunload", cleanup); -} diff --git a/examples/tutorials/nhost-vue-tutorial/src/main.ts b/examples/tutorials/nhost-vue-tutorial/src/main.ts deleted file mode 100644 index 7a9c7a853..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -import "./assets/main.css"; - -import { createApp } from "vue"; -import App from "./App.vue"; -import router from "./router"; - -const app = createApp(App); - -app.use(router); - -app.mount("#app"); diff --git a/examples/tutorials/nhost-vue-tutorial/src/router/index.ts b/examples/tutorials/nhost-vue-tutorial/src/router/index.ts deleted file mode 100644 index 45cb95082..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/router/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { createRouter, createWebHistory } from "vue-router"; -import { useAuth } from "../lib/nhost/auth"; -import Files from "../views/Files.vue"; -import HomeView from "../views/HomeView.vue"; -import ProfileView from "../views/ProfileView.vue"; -import SignIn from "../views/SignIn.vue"; -import SignUp from "../views/SignUp.vue"; -import Todos from "../views/Todos.vue"; -import Verify from "../views/Verify.vue"; - -const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - routes: [ - { - path: "/", - name: "home", - component: HomeView, - }, - { - path: "/signin", - name: "SignIn", - component: SignIn, - }, - { - path: "/signup", - name: "SignUp", - component: SignUp, - }, - { - path: "/verify", - name: "Verify", - component: Verify, - }, - { - path: "/profile", - name: "profile", - component: ProfileView, - meta: { requiresAuth: true }, - }, - { - path: "/todos", - name: "Todos", - component: Todos, - meta: { requiresAuth: true }, - }, - { - path: "/files", - name: "Files", - component: Files, - meta: { requiresAuth: true }, - }, - { - path: "/:pathMatch(.*)*", - redirect: "/", - }, - ], -}); - -// Navigation guard for protected routes -router.beforeEach((to) => { - if (to.meta["requiresAuth"]) { - const { isAuthenticated, isLoading } = useAuth(); - - // Show loading state while authentication is being checked - if (isLoading.value) { - // You can return a loading component path or handle loading in the component - return true; // Allow navigation, handle loading in component - } - - if (!isAuthenticated.value) { - return "/"; // Redirect to home page - } - } - return true; -}); - -export default router; diff --git a/examples/tutorials/nhost-vue-tutorial/src/views/AboutView.vue b/examples/tutorials/nhost-vue-tutorial/src/views/AboutView.vue deleted file mode 100644 index 756ad2a17..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/views/AboutView.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/views/Files.vue b/examples/tutorials/nhost-vue-tutorial/src/views/Files.vue deleted file mode 100644 index 60304e8a9..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/views/Files.vue +++ /dev/null @@ -1,394 +0,0 @@ - - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/views/HomeView.vue b/examples/tutorials/nhost-vue-tutorial/src/views/HomeView.vue deleted file mode 100644 index 200bde705..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/views/HomeView.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/views/ProfileView.vue b/examples/tutorials/nhost-vue-tutorial/src/views/ProfileView.vue deleted file mode 100644 index 63479d29a..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/views/ProfileView.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/views/SignIn.vue b/examples/tutorials/nhost-vue-tutorial/src/views/SignIn.vue deleted file mode 100644 index 085cbea0c..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/views/SignIn.vue +++ /dev/null @@ -1,96 +0,0 @@ - - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/views/SignUp.vue b/examples/tutorials/nhost-vue-tutorial/src/views/SignUp.vue deleted file mode 100644 index 18f0a82ef..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/views/SignUp.vue +++ /dev/null @@ -1,131 +0,0 @@ - - - diff --git a/examples/tutorials/nhost-vue-tutorial/src/views/Todos.vue b/examples/tutorials/nhost-vue-tutorial/src/views/Todos.vue deleted file mode 100644 index cce16e0f3..000000000 --- a/examples/tutorials/nhost-vue-tutorial/src/views/Todos.vue +++ /dev/null @@ -1,466 +0,0 @@ -