chore: Run prettier on examples folder (#43851)

This PR runs `prettier` on the `examples` folder.

Depends on https://github.com/supabase/supabase/pull/43849.
This commit is contained in:
Ivan Vasilov authored and GitHub committed 2026-03-18 10:51:10 +01:00
1 parent 0aa54d95f4
commit d07e78a616
343 files changed
+11828 -16637

No files matched your search

+1 -1
View File
@@ -51,4 +51,4 @@
"reactCompiler": true
}
}
}
}
@@ -1,17 +1,18 @@
import { Tabs } from 'expo-router';
import { Tabs } from 'expo-router'
import { Colors } from '@/constants/theme';
import { useColorScheme } from '@/hooks/use-color-scheme';
import { Colors } from '@/constants/theme'
import { useColorScheme } from '@/hooks/use-color-scheme'
export default function TabLayout() {
const colorScheme = useColorScheme();
const colorScheme = useColorScheme()
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
headerShown: false,
}}>
}}
>
<Tabs.Screen
name="index"
options={{
@@ -19,5 +20,5 @@ export default function TabLayout() {
}}
/>
</Tabs>
);
)
}
@@ -1,8 +1,8 @@
import { Link, Stack } from 'expo-router';
import { StyleSheet } from 'react-native';
import { Link, Stack } from 'expo-router'
import { StyleSheet } from 'react-native'
import { ThemedText } from '@/components/themed-text';
import { ThemedView } from '@/components/themed-view';
import { ThemedText } from '@/components/themed-text'
import { ThemedView } from '@/components/themed-view'
export default function NotFoundScreen() {
return (
@@ -15,7 +15,7 @@ export default function NotFoundScreen() {
</Link>
</ThemedView>
</>
);
)
}
const styles = StyleSheet.create({
@@ -29,4 +29,4 @@ const styles = StyleSheet.create({
marginTop: 15,
paddingVertical: 15,
},
});
})
@@ -1,34 +1,34 @@
import { useEffect } from 'react';
import { StyleSheet } from 'react-native';
import { useEffect } from 'react'
import { StyleSheet } from 'react-native'
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
withRepeat,
withSequence,
} from 'react-native-reanimated';
} from 'react-native-reanimated'
import { ThemedText } from '@/components/themed-text';
import { ThemedText } from '@/components/themed-text'
export function HelloWave() {
const rotationAnimation = useSharedValue(0);
const rotationAnimation = useSharedValue(0)
useEffect(() => {
rotationAnimation.value = withRepeat(
withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })),
4
);
}, [rotationAnimation]);
)
}, [rotationAnimation])
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ rotate: `${rotationAnimation.value}deg` }],
}));
}))
return (
<Animated.View style={animatedStyle}>
<ThemedText style={styles.text}>👋</ThemedText>
</Animated.View>
);
)
}
const styles = StyleSheet.create({
@@ -37,4 +37,4 @@ const styles = StyleSheet.create({
lineHeight: 32,
marginTop: -6,
},
});
})
@@ -1,30 +1,30 @@
import type { PropsWithChildren, ReactElement } from 'react';
import { StyleSheet } from 'react-native';
import type { PropsWithChildren, ReactElement } from 'react'
import { StyleSheet } from 'react-native'
import Animated, {
interpolate,
useAnimatedRef,
useAnimatedStyle,
useScrollViewOffset,
} from 'react-native-reanimated';
} from 'react-native-reanimated'
import { ThemedView } from '@/components/themed-view';
import { useColorScheme } from '@/hooks/use-color-scheme';
import { ThemedView } from '@/components/themed-view'
import { useColorScheme } from '@/hooks/use-color-scheme'
const HEADER_HEIGHT = 250;
const HEADER_HEIGHT = 250
type Props = PropsWithChildren<{
headerImage: ReactElement;
headerBackgroundColor: { dark: string; light: string };
}>;
headerImage: ReactElement
headerBackgroundColor: { dark: string; light: string }
}>
export default function ParallaxScrollView({
children,
headerImage,
headerBackgroundColor,
}: Props) {
const colorScheme = useColorScheme() ?? 'light';
const scrollRef = useAnimatedRef<Animated.ScrollView>();
const scrollOffset = useScrollViewOffset(scrollRef);
const colorScheme = useColorScheme() ?? 'light'
const scrollRef = useAnimatedRef<Animated.ScrollView>()
const scrollOffset = useScrollViewOffset(scrollRef)
const headerAnimatedStyle = useAnimatedStyle(() => {
return {
@@ -40,8 +40,8 @@ export default function ParallaxScrollView({
scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]),
},
],
};
});
}
})
return (
<ThemedView style={styles.container}>
@@ -51,13 +51,14 @@ export default function ParallaxScrollView({
styles.header,
{ backgroundColor: headerBackgroundColor[colorScheme] },
headerAnimatedStyle,
]}>
]}
>
{headerImage}
</Animated.View>
<ThemedView style={styles.content}>{children}</ThemedView>
</Animated.ScrollView>
</ThemedView>
);
)
}
const styles = StyleSheet.create({
@@ -74,4 +75,4 @@ const styles = StyleSheet.create({
gap: 16,
overflow: 'hidden',
},
});
})
@@ -1,14 +1,14 @@
import { supabase } from '@/lib/supabase';
import { appleAuthAndroid, AppleButton } from '@invertase/react-native-apple-authentication';
import { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { Platform } from 'react-native';
import 'react-native-get-random-values';
import { v4 as uuid } from 'uuid';
import { supabase } from '@/lib/supabase'
import { appleAuthAndroid, AppleButton } from '@invertase/react-native-apple-authentication'
import { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { Platform } from 'react-native'
import 'react-native-get-random-values'
import { v4 as uuid } from 'uuid'
async function onAppleButtonPress() {
// Generate secure, random values for state and nonce
const rawNonce = uuid();
const state = uuid();
const rawNonce = uuid()
const state = uuid()
// Configure the request
appleAuthAndroid.configure({
@@ -30,11 +30,11 @@ async function onAppleButtonPress() {
// Unique state value used to prevent CSRF attacks. A UUID will be generated if nothing is provided.
state,
});
})
// Open the browser window for user sign in
const credentialState = await appleAuthAndroid.signIn();
console.log('Apple sign in successful:', credentialState);
const credentialState = await appleAuthAndroid.signIn()
console.log('Apple sign in successful:', credentialState)
if (credentialState.id_token && credentialState.code && credentialState.nonce) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
@@ -42,26 +42,30 @@ async function onAppleButtonPress() {
token: credentialState.id_token,
nonce: credentialState.nonce,
access_token: credentialState.code,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials);
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Apple:', error);
console.error('Error signing in with Apple:', error)
}
if (data) {
console.log('Apple sign in successful:', data);
console.log('Apple sign in successful:', data)
}
}
}
export default function AppleSignInButton() {
if (Platform.OS !== 'android' || appleAuthAndroid.isSupported !== true) { return <></> }
if (Platform.OS !== 'android' || appleAuthAndroid.isSupported !== true) {
return <></>
}
return <AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
onPress={() => onAppleButtonPress()}
/>;
return (
<AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
onPress={() => onAppleButtonPress()}
/>
)
}
@@ -1,8 +1,8 @@
import { supabase } from '@/lib/supabase';
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication';
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { router } from 'expo-router';
import { Platform } from 'react-native';
import { supabase } from '@/lib/supabase'
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication'
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { router } from 'expo-router'
import { Platform } from 'react-native'
async function onAppleButtonPress() {
// Performs login request
@@ -10,42 +10,50 @@ async function onAppleButtonPress() {
requestedOperation: appleAuth.Operation.LOGIN,
// Note: it appears putting FULL_NAME first is important, see issue #293
requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL],
});
})
// Get the current authentication state for user
// Note: This method must be tested on a real device. On the iOS simulator it always throws an error.
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user)
console.log('Apple sign in successful:', { credentialState, appleAuthRequestResponse });
console.log('Apple sign in successful:', { credentialState, appleAuthRequestResponse })
if (credentialState === appleAuth.State.AUTHORIZED && appleAuthRequestResponse.identityToken && appleAuthRequestResponse.authorizationCode) {
if (
credentialState === appleAuth.State.AUTHORIZED &&
appleAuthRequestResponse.identityToken &&
appleAuthRequestResponse.authorizationCode
) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
provider: 'apple',
token: appleAuthRequestResponse.identityToken,
nonce: appleAuthRequestResponse.nonce,
access_token: appleAuthRequestResponse.authorizationCode,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials);
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Apple:', error);
console.error('Error signing in with Apple:', error)
}
if (data) {
console.log('Apple sign in successful:', data);
router.navigate('/(tabs)');
console.log('Apple sign in successful:', data)
router.navigate('/(tabs)')
}
}
}
export default function AppleSignInButton() {
if (Platform.OS !== 'ios') { return <></>; }
if (Platform.OS !== 'ios') {
return <></>
}
return <AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
style={{ width: 160, height: 45 }}
onPress={() => onAppleButtonPress()}
/>;
return (
<AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
style={{ width: 160, height: 45 }}
onPress={() => onAppleButtonPress()}
/>
)
}
@@ -1,8 +1,8 @@
import { supabase } from '@/lib/supabase';
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication';
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { router } from 'expo-router';
import { Platform } from 'react-native';
import { supabase } from '@/lib/supabase'
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication'
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { router } from 'expo-router'
import { Platform } from 'react-native'
async function onAppleButtonPress() {
// Performs login request
@@ -10,42 +10,50 @@ async function onAppleButtonPress() {
requestedOperation: appleAuth.Operation.LOGIN,
// Note: it appears putting FULL_NAME first is important, see issue #293
requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL],
});
})
// Get the current authentication state for user
// Note: This method must be tested on a real device. On the iOS simulator it always throws an error.
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user)
console.log('Apple sign in successful:', { credentialState, appleAuthRequestResponse });
console.log('Apple sign in successful:', { credentialState, appleAuthRequestResponse })
if (credentialState === appleAuth.State.AUTHORIZED && appleAuthRequestResponse.identityToken && appleAuthRequestResponse.authorizationCode) {
if (
credentialState === appleAuth.State.AUTHORIZED &&
appleAuthRequestResponse.identityToken &&
appleAuthRequestResponse.authorizationCode
) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
provider: 'apple',
token: appleAuthRequestResponse.identityToken,
nonce: appleAuthRequestResponse.nonce,
access_token: appleAuthRequestResponse.authorizationCode,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials);
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Apple:', error);
console.error('Error signing in with Apple:', error)
}
if (data) {
console.log('Apple sign in successful:', data);
router.navigate('/(tabs)');
console.log('Apple sign in successful:', data)
router.navigate('/(tabs)')
}
}
}
export default function AppleSignInButton() {
if (Platform.OS !== 'ios') { return <></>; }
if (Platform.OS !== 'ios') {
return <></>
}
return <AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
style={{ width: 160, height: 45 }}
onPress={() => onAppleButtonPress()}
/>;
return (
<AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
style={{ width: 160, height: 45 }}
onPress={() => onAppleButtonPress()}
/>
)
}
@@ -1,68 +1,77 @@
import { supabase } from '@/lib/supabase';
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { useEffect, useState } from 'react';
import AppleSignin, { type AppleAuthResponse } from 'react-apple-signin-auth';
import { Platform } from 'react-native';
import { supabase } from '@/lib/supabase'
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { useEffect, useState } from 'react'
import AppleSignin, { type AppleAuthResponse } from 'react-apple-signin-auth'
import { Platform } from 'react-native'
export default function AppleSignInButton() {
const [nonce, setNonce] = useState('');
const [sha256Nonce, setSha256Nonce] = useState('');
const [nonce, setNonce] = useState('')
const [sha256Nonce, setSha256Nonce] = useState('')
async function onAppleButtonSuccess(appleAuthRequestResponse: AppleAuthResponse) {
console.debug('Apple sign in successful:', { appleAuthRequestResponse });
if (appleAuthRequestResponse.authorization && appleAuthRequestResponse.authorization.id_token && appleAuthRequestResponse.authorization.code) {
console.debug('Apple sign in successful:', { appleAuthRequestResponse })
if (
appleAuthRequestResponse.authorization &&
appleAuthRequestResponse.authorization.id_token &&
appleAuthRequestResponse.authorization.code
) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
provider: 'apple',
token: appleAuthRequestResponse.authorization.id_token,
nonce,
access_token: appleAuthRequestResponse.authorization.code,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Apple:', error);
console.error('Error signing in with Apple:', error)
}
if (data) {
console.log('Apple sign in successful:', data);
console.log('Apple sign in successful:', data)
}
};
}
}
useEffect(() => {
function generateNonce(): string {
const array = new Uint32Array(1);
window.crypto.getRandomValues(array);
return array[0].toString();
};
async function generateSha256Nonce(nonce: string): Promise<string> {
const buffer = await window.crypto.subtle.digest('sha-256', new TextEncoder().encode(nonce));
const array = Array.from(new Uint8Array(buffer));
return array.map(b => b.toString(16).padStart(2, '0')).join('');
const array = new Uint32Array(1)
window.crypto.getRandomValues(array)
return array[0].toString()
}
let nonce = generateNonce();
setNonce(nonce);
async function generateSha256Nonce(nonce: string): Promise<string> {
const buffer = await window.crypto.subtle.digest('sha-256', new TextEncoder().encode(nonce))
const array = Array.from(new Uint8Array(buffer))
return array.map((b) => b.toString(16).padStart(2, '0')).join('')
}
generateSha256Nonce(nonce)
.then((sha256Nonce) => { setSha256Nonce(sha256Nonce) });
}, []);
let nonce = generateNonce()
setNonce(nonce)
if (Platform.OS !== 'web') { return <></>; }
generateSha256Nonce(nonce).then((sha256Nonce) => {
setSha256Nonce(sha256Nonce)
})
}, [])
return <AppleSignin
authOptions={{
clientId: process.env.EXPO_PUBLIC_APPLE_AUTH_SERVICE_ID ?? '',
redirectURI: process.env.EXPO_PUBLIC_APPLE_AUTH_REDIRECT_URI ?? '',
scope: 'email name',
state: 'state',
nonce: sha256Nonce,
usePopup: true,
}}
uiType="dark"
onSuccess={onAppleButtonSuccess}
onError={(error: any) => console.error('Apple sign in error:', error)}
/>;
if (Platform.OS !== 'web') {
return <></>
}
return (
<AppleSignin
authOptions={{
clientId: process.env.EXPO_PUBLIC_APPLE_AUTH_SERVICE_ID ?? '',
redirectURI: process.env.EXPO_PUBLIC_APPLE_AUTH_REDIRECT_URI ?? '',
scope: 'email name',
state: 'state',
nonce: sha256Nonce,
usePopup: true,
}}
uiType="dark"
onSuccess={onAppleButtonSuccess}
onError={(error: any) => console.error('Apple sign in error:', error)}
/>
)
}
@@ -1,90 +1,89 @@
import { supabase } from '@/lib/supabase';
import { useEffect } from 'react';
import { TouchableOpacity } from 'react-native';
import { supabase } from '@/lib/supabase'
import { useEffect } from 'react'
import { TouchableOpacity } from 'react-native'
import { expo } from '@/app.json';
import { Text } from '@react-navigation/elements';
import { Image } from 'expo-image';
import * as WebBrowser from "expo-web-browser";
import { expo } from '@/app.json'
import { Text } from '@react-navigation/elements'
import { Image } from 'expo-image'
import * as WebBrowser from 'expo-web-browser'
WebBrowser.maybeCompleteAuthSession();
WebBrowser.maybeCompleteAuthSession()
export default function GoogleSignInButton() {
function extractParamsFromUrl(url: string) {
const parsedUrl = new URL(url);
const hash = parsedUrl.hash.substring(1); // Remove the leading '#'
const params = new URLSearchParams(hash);
const parsedUrl = new URL(url)
const hash = parsedUrl.hash.substring(1) // Remove the leading '#'
const params = new URLSearchParams(hash)
return {
access_token: params.get("access_token"),
expires_in: parseInt(params.get("expires_in") || "0"),
refresh_token: params.get("refresh_token"),
token_type: params.get("token_type"),
provider_token: params.get("provider_token"),
code: params.get("code"),
};
};
access_token: params.get('access_token'),
expires_in: parseInt(params.get('expires_in') || '0'),
refresh_token: params.get('refresh_token'),
token_type: params.get('token_type'),
provider_token: params.get('provider_token'),
code: params.get('code'),
}
}
async function onSignInButtonPress() {
console.debug('onSignInButtonPress - start');
console.debug('onSignInButtonPress - start')
const res = await supabase.auth.signInWithOAuth({
provider: "google",
provider: 'google',
options: {
redirectTo: `${expo.scheme}://google-auth`,
queryParams: { prompt: "consent" },
queryParams: { prompt: 'consent' },
skipBrowserRedirect: true,
},
});
})
const googleOAuthUrl = res.data.url;
const googleOAuthUrl = res.data.url
if (!googleOAuthUrl) {
console.error("no oauth url found!");
return;
console.error('no oauth url found!')
return
}
const result = await WebBrowser.openAuthSessionAsync(
googleOAuthUrl,
`${expo.scheme}://google-auth`,
{ showInRecents: true },
{ showInRecents: true }
).catch((err) => {
console.error('onSignInButtonPress - openAuthSessionAsync - error', { err });
console.log(err);
});
console.error('onSignInButtonPress - openAuthSessionAsync - error', { err })
console.log(err)
})
console.debug('onSignInButtonPress - openAuthSessionAsync - result', { result });
console.debug('onSignInButtonPress - openAuthSessionAsync - result', { result })
if (result && result.type === "success") {
console.debug('onSignInButtonPress - openAuthSessionAsync - success');
const params = extractParamsFromUrl(result.url);
console.debug('onSignInButtonPress - openAuthSessionAsync - success', { params });
if (result && result.type === 'success') {
console.debug('onSignInButtonPress - openAuthSessionAsync - success')
const params = extractParamsFromUrl(result.url)
console.debug('onSignInButtonPress - openAuthSessionAsync - success', { params })
if (params.access_token && params.refresh_token) {
console.debug('onSignInButtonPress - setSession');
console.debug('onSignInButtonPress - setSession')
const { data, error } = await supabase.auth.setSession({
access_token: params.access_token,
refresh_token: params.refresh_token,
});
console.debug('onSignInButtonPress - setSession - success', { data, error });
return;
})
console.debug('onSignInButtonPress - setSession - success', { data, error })
return
} else {
console.error('onSignInButtonPress - setSession - failed');
console.error('onSignInButtonPress - setSession - failed')
// sign in/up failed
}
} else {
console.error('onSignInButtonPress - openAuthSessionAsync - failed');
console.error('onSignInButtonPress - openAuthSessionAsync - failed')
}
}
// to warm up the browser
useEffect(() => {
WebBrowser.warmUpAsync();
WebBrowser.warmUpAsync()
return () => {
WebBrowser.coolDownAsync();
};
}, []);
WebBrowser.coolDownAsync()
}
}, [])
return (
<TouchableOpacity
@@ -122,5 +121,5 @@ export default function GoogleSignInButton() {
Sign in with Google
</Text>
</TouchableOpacity>
);
)
}
@@ -1,60 +1,60 @@
import { supabase } from '@/lib/supabase';
import { CredentialResponse, GoogleLogin, GoogleOAuthProvider } from '@react-oauth/google';
import { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { useEffect, useState } from 'react';
import { supabase } from '@/lib/supabase'
import { CredentialResponse, GoogleLogin, GoogleOAuthProvider } from '@react-oauth/google'
import { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { useEffect, useState } from 'react'
import 'react-native-get-random-values';
import 'react-native-get-random-values'
export default function GoogleSignInButton() {
// Generate secure, random values for state and nonce
const [nonce, setNonce] = useState('');
const [sha256Nonce, setSha256Nonce] = useState('');
const [nonce, setNonce] = useState('')
const [sha256Nonce, setSha256Nonce] = useState('')
async function onGoogleButtonSuccess(authRequestResponse: CredentialResponse) {
console.debug('Google sign in successful:', { authRequestResponse });
console.debug('Google sign in successful:', { authRequestResponse })
if (authRequestResponse.clientId && authRequestResponse.credential) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
provider: 'google',
token: authRequestResponse.credential,
nonce: nonce,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials);
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Google:', error);
console.error('Error signing in with Google:', error)
}
if (data) {
console.log('Google sign in successful:', data);
console.log('Google sign in successful:', data)
}
}
}
function onGoogleButtonFailure() {
console.error('Error signing in with Google');
console.error('Error signing in with Google')
}
useEffect(() => {
function generateNonce(): string {
const array = new Uint32Array(1);
window.crypto.getRandomValues(array);
return array[0].toString();
const array = new Uint32Array(1)
window.crypto.getRandomValues(array)
return array[0].toString()
}
async function generateSha256Nonce(nonce: string): Promise<string> {
const buffer = await window.crypto.subtle.digest('sha-256', new TextEncoder().encode(nonce));
const array = Array.from(new Uint8Array(buffer));
return array.map(b => b.toString(16).padStart(2, '0')).join('');
const buffer = await window.crypto.subtle.digest('sha-256', new TextEncoder().encode(nonce))
const array = Array.from(new Uint8Array(buffer))
return array.map((b) => b.toString(16).padStart(2, '0')).join('')
}
let nonce = generateNonce();
setNonce(nonce);
let nonce = generateNonce()
setNonce(nonce)
generateSha256Nonce(nonce)
.then((sha256Nonce) => { setSha256Nonce(sha256Nonce) });
}, []);
generateSha256Nonce(nonce).then((sha256Nonce) => {
setSha256Nonce(sha256Nonce)
})
}, [])
return (
<GoogleOAuthProvider
@@ -69,5 +69,5 @@ export default function GoogleSignInButton() {
auto_select={true}
/>
</GoogleOAuthProvider>
);
)
}
@@ -1,13 +1,13 @@
import { Text, type TextProps, StyleSheet } from 'react-native';
import { Text, type TextProps, StyleSheet } from 'react-native'
import { useThemeColor } from '@/hooks/use-theme-color';
import { Fonts } from '@/constants/theme';
import { useThemeColor } from '@/hooks/use-theme-color'
import { Fonts } from '@/constants/theme'
export type ThemedTextProps = TextProps & {
lightColor?: string;
darkColor?: string;
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
};
lightColor?: string
darkColor?: string
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'
}
export function ThemedText({
style,
@@ -16,7 +16,7 @@ export function ThemedText({
type = 'default',
...rest
}: ThemedTextProps) {
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text')
return (
<Text
@@ -31,7 +31,7 @@ export function ThemedText({
]}
{...rest}
/>
);
)
}
const styles = StyleSheet.create({
@@ -58,4 +58,4 @@ const styles = StyleSheet.create({
fontSize: 16,
color: '#0a7ea4',
},
});
})
@@ -1,14 +1,14 @@
import { View, type ViewProps } from 'react-native';
import { View, type ViewProps } from 'react-native'
import { useThemeColor } from '@/hooks/use-theme-color';
import { useThemeColor } from '@/hooks/use-theme-color'
export type ThemedViewProps = ViewProps & {
lightColor?: string;
darkColor?: string;
};
lightColor?: string
darkColor?: string
}
export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background')
return <View style={[{ backgroundColor }, style]} {...otherProps} />;
return <View style={[{ backgroundColor }, style]} {...otherProps} />
}
@@ -3,10 +3,10 @@
* There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
*/
import { Platform } from 'react-native';
import { Platform } from 'react-native'
const tintColorLight = '#0a7ea4';
const tintColorDark = '#fff';
const tintColorLight = '#0a7ea4'
const tintColorDark = '#fff'
export const Colors = {
light: {
@@ -25,7 +25,7 @@ export const Colors = {
tabIconDefault: '#9BA1A6',
tabIconSelected: tintColorDark,
},
};
}
export const Fonts = Platform.select({
ios: {
@@ -50,4 +50,4 @@ export const Fonts = Platform.select({
rounded: "'SF Pro Rounded', 'Hiragino Maru Gothic ProN', Meiryo, 'MS PGothic', sans-serif",
mono: "SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
},
});
})
@@ -1,10 +1,10 @@
// https://docs.expo.dev/guides/using-eslint/
const { defineConfig } = require('eslint/config');
const expoConfig = require('eslint-config-expo/flat');
const { defineConfig } = require('eslint/config')
const expoConfig = require('eslint-config-expo/flat')
module.exports = defineConfig([
expoConfig,
{
ignores: ['dist/*'],
},
]);
])
@@ -1 +1 @@
export { useColorScheme } from 'react-native';
export { useColorScheme } from 'react-native'
@@ -1,21 +1,21 @@
import { useEffect, useState } from 'react';
import { useColorScheme as useRNColorScheme } from 'react-native';
import { useEffect, useState } from 'react'
import { useColorScheme as useRNColorScheme } from 'react-native'
/**
* To support static rendering, this value needs to be re-calculated on the client side for web
*/
export function useColorScheme() {
const [hasHydrated, setHasHydrated] = useState(false);
const [hasHydrated, setHasHydrated] = useState(false)
useEffect(() => {
setHasHydrated(true);
}, []);
setHasHydrated(true)
}, [])
const colorScheme = useRNColorScheme();
const colorScheme = useRNColorScheme()
if (hasHydrated) {
return colorScheme;
return colorScheme
}
return 'light';
return 'light'
}
@@ -3,19 +3,19 @@
* https://docs.expo.dev/guides/color-schemes/
*/
import { Colors } from '@/constants/theme';
import { useColorScheme } from '@/hooks/use-color-scheme';
import { Colors } from '@/constants/theme'
import { useColorScheme } from '@/hooks/use-color-scheme'
export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
) {
const theme = useColorScheme() ?? 'light';
const colorFromProps = props[theme];
const theme = useColorScheme() ?? 'light'
const colorFromProps = props[theme]
if (colorFromProps) {
return colorFromProps;
return colorFromProps
} else {
return Colors[theme][colorName];
return Colors[theme][colorName]
}
}
@@ -1,21 +1,23 @@
import { createClient } from '@supabase/supabase-js';
import { deleteItemAsync, getItemAsync, setItemAsync } from 'expo-secure-store';
import { createClient } from '@supabase/supabase-js'
import { deleteItemAsync, getItemAsync, setItemAsync } from 'expo-secure-store'
const ExpoSecureStoreAdapter = {
getItem: (key: string) => {
console.debug("getItem", { key, getItemAsync })
console.debug('getItem', { key, getItemAsync })
return getItemAsync(key)
},
setItem: (key: string, value: string) => {
if (value.length > 2048) {
console.warn('Value being stored in SecureStore is larger than 2048 bytes and it may not be stored successfully. In a future SDK version, this call may throw an error.')
console.warn(
'Value being stored in SecureStore is larger than 2048 bytes and it may not be stored successfully. In a future SDK version, this call may throw an error.'
)
}
return setItemAsync(key, value)
},
removeItem: (key: string) => {
return deleteItemAsync(key)
},
};
}
export const supabase = createClient(
process.env.EXPO_PUBLIC_SUPABASE_URL ?? '',
@@ -27,5 +29,5 @@ export const supabase = createClient(
persistSession: true,
detectSessionInUrl: false,
},
},
);
}
)
@@ -1,24 +1,24 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createClient } from '@supabase/supabase-js';
import 'react-native-url-polyfill/auto';
import AsyncStorage from '@react-native-async-storage/async-storage'
import { createClient } from '@supabase/supabase-js'
import 'react-native-url-polyfill/auto'
const isSSR = typeof window === 'undefined';
const isSSR = typeof window === 'undefined'
const ExpoWebSecureStoreAdapter = {
getItem: (key: string) => {
if (isSSR) return null;
console.debug("getItem", { key })
if (isSSR) return null
console.debug('getItem', { key })
return AsyncStorage.getItem(key)
},
setItem: (key: string, value: string) => {
if (isSSR) return;
if (isSSR) return
return AsyncStorage.setItem(key, value)
},
removeItem: (key: string) => {
if (isSSR) return;
if (isSSR) return
return AsyncStorage.removeItem(key)
},
};
}
export const supabase = createClient(
process.env.EXPO_PUBLIC_SUPABASE_URL ?? '',
@@ -30,5 +30,5 @@ export const supabase = createClient(
persistSession: true,
detectSessionInUrl: false,
},
},
);
}
)
+61 -184
View File
@@ -4231,219 +4231,157 @@
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
"integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
"os": ["android"]
},
"node_modules/@unrs/resolver-binding-android-arm64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz",
"integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
"os": ["android"]
},
"node_modules/@unrs/resolver-binding-darwin-arm64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz",
"integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
"os": ["darwin"]
},
"node_modules/@unrs/resolver-binding-darwin-x64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz",
"integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
"os": ["darwin"]
},
"node_modules/@unrs/resolver-binding-freebsd-x64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz",
"integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
"os": ["freebsd"]
},
"node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz",
"integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz",
"integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
"integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-arm64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz",
"integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz",
"integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz",
"integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz",
"integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz",
"integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==",
"cpu": [
"s390x"
],
"cpu": ["s390x"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-x64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz",
"integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-x64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz",
"integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-wasm32-wasi": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz",
"integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==",
"cpu": [
"wasm32"
],
"cpu": ["wasm32"],
"dev": true,
"license": "MIT",
"optional": true,
@@ -4458,43 +4396,31 @@
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz",
"integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz",
"integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@unrs/resolver-binding-win32-x64-msvc": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz",
"integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@urql/core": {
"version": "5.2.0",
@@ -7304,9 +7230,7 @@
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
@@ -8811,14 +8735,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
"integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8831,14 +8751,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
"integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8851,14 +8767,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
"integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8871,14 +8783,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
"integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"freebsd"
],
"os": ["freebsd"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8891,14 +8799,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
"integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8911,14 +8815,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
"integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8931,14 +8831,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
"integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8951,14 +8847,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
"integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8971,14 +8863,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
"integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8991,14 +8879,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
"integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">= 12.0.0"
},
@@ -9011,14 +8895,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
"integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">= 12.0.0"
},
@@ -12897,10 +12777,7 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
"dev": true,
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"funding": ["https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan"],
"license": "MIT",
"bin": {
"uuid": "dist-node/bin/uuid"
@@ -44,11 +44,7 @@ export default function AuthProvider({ children }: PropsWithChildren) {
setIsLoading(true)
if (claims) {
const { data } = await supabase
.from('profiles')
.select('*')
.eq('id', claims.sub)
.single()
const { data } = await supabase.from('profiles').select('*').eq('id', claims.sub).single()
setProfile(data)
} else {
@@ -6,15 +6,15 @@
* You can remove the `reset-project` script from package.json and safely delete this file after running it.
*/
const fs = require("fs");
const path = require("path");
const readline = require("readline");
const fs = require('fs')
const path = require('path')
const readline = require('readline')
const root = process.cwd();
const oldDirs = ["app", "components", "hooks", "constants", "scripts"];
const exampleDir = "app-example";
const newAppDir = "app";
const exampleDirPath = path.join(root, exampleDir);
const root = process.cwd()
const oldDirs = ['app', 'components', 'hooks', 'constants', 'scripts']
const exampleDir = 'app-example'
const newAppDir = 'app'
const exampleDirPath = path.join(root, exampleDir)
const indexContent = `import { Text, View } from "react-native";
@@ -31,82 +31,82 @@ export default function Index() {
</View>
);
}
`;
`
const layoutContent = `import { Stack } from "expo-router";
export default function RootLayout() {
return <Stack />;
}
`;
`
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
})
const moveDirectories = async (userInput) => {
try {
if (userInput === "y") {
if (userInput === 'y') {
// Create the app-example directory
await fs.promises.mkdir(exampleDirPath, { recursive: true });
console.log(`📁 /${exampleDir} directory created.`);
await fs.promises.mkdir(exampleDirPath, { recursive: true })
console.log(`📁 /${exampleDir} directory created.`)
}
// Move old directories to new app-example directory or delete them
for (const dir of oldDirs) {
const oldDirPath = path.join(root, dir);
const oldDirPath = path.join(root, dir)
if (fs.existsSync(oldDirPath)) {
if (userInput === "y") {
const newDirPath = path.join(root, exampleDir, dir);
await fs.promises.rename(oldDirPath, newDirPath);
console.log(`➡️ /${dir} moved to /${exampleDir}/${dir}.`);
if (userInput === 'y') {
const newDirPath = path.join(root, exampleDir, dir)
await fs.promises.rename(oldDirPath, newDirPath)
console.log(`➡️ /${dir} moved to /${exampleDir}/${dir}.`)
} else {
await fs.promises.rm(oldDirPath, { recursive: true, force: true });
console.log(`❌ /${dir} deleted.`);
await fs.promises.rm(oldDirPath, { recursive: true, force: true })
console.log(`❌ /${dir} deleted.`)
}
} else {
console.log(`➡️ /${dir} does not exist, skipping.`);
console.log(`➡️ /${dir} does not exist, skipping.`)
}
}
// Create new /app directory
const newAppDirPath = path.join(root, newAppDir);
await fs.promises.mkdir(newAppDirPath, { recursive: true });
console.log("\n📁 New /app directory created.");
const newAppDirPath = path.join(root, newAppDir)
await fs.promises.mkdir(newAppDirPath, { recursive: true })
console.log('\n📁 New /app directory created.')
// Create index.tsx
const indexPath = path.join(newAppDirPath, "index.tsx");
await fs.promises.writeFile(indexPath, indexContent);
console.log("📄 app/index.tsx created.");
const indexPath = path.join(newAppDirPath, 'index.tsx')
await fs.promises.writeFile(indexPath, indexContent)
console.log('📄 app/index.tsx created.')
// Create _layout.tsx
const layoutPath = path.join(newAppDirPath, "_layout.tsx");
await fs.promises.writeFile(layoutPath, layoutContent);
console.log("📄 app/_layout.tsx created.");
const layoutPath = path.join(newAppDirPath, '_layout.tsx')
await fs.promises.writeFile(layoutPath, layoutContent)
console.log('📄 app/_layout.tsx created.')
console.log("\n✅ Project reset complete. Next steps:");
console.log('\n✅ Project reset complete. Next steps:')
console.log(
`1. Run \`npx expo start\` to start a development server.\n2. Edit app/index.tsx to edit the main screen.${
userInput === "y"
userInput === 'y'
? `\n3. Delete the /${exampleDir} directory when you're done referencing it.`
: ""
: ''
}`
);
)
} catch (error) {
console.error(`❌ Error during script execution: ${error.message}`);
console.error(`❌ Error during script execution: ${error.message}`)
}
};
}
rl.question(
"Do you want to move existing files to /app-example instead of deleting them? (Y/n): ",
'Do you want to move existing files to /app-example instead of deleting them? (Y/n): ',
(answer) => {
const userInput = answer.trim().toLowerCase() || "y";
if (userInput === "y" || userInput === "n") {
moveDirectories(userInput).finally(() => rl.close());
const userInput = answer.trim().toLowerCase() || 'y'
if (userInput === 'y' || userInput === 'n') {
moveDirectories(userInput).finally(() => rl.close())
} else {
console.log("❌ Invalid input. Please enter 'Y' or 'N'.");
rl.close();
console.log("❌ Invalid input. Please enter 'Y' or 'N'.")
rl.close()
}
}
);
)
+2 -9
View File
@@ -3,15 +3,8 @@
"compilerOptions": {
"strict": true,
"paths": {
"@/*": [
"./*"
]
"@/*": ["./*"]
}
},
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts"
]
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}
@@ -1,122 +1,122 @@
{
"images" : [
"images": [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"size": "20x20",
"idiom": "iphone",
"filename": "Icon-App-20x20@2x.png",
"scale": "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
"size": "20x20",
"idiom": "iphone",
"filename": "Icon-App-20x20@3x.png",
"scale": "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@1x.png",
"scale": "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@2x.png",
"scale": "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@3x.png",
"scale": "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"size": "40x40",
"idiom": "iphone",
"filename": "Icon-App-40x40@2x.png",
"scale": "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
"size": "40x40",
"idiom": "iphone",
"filename": "Icon-App-40x40@3x.png",
"scale": "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
"size": "60x60",
"idiom": "iphone",
"filename": "Icon-App-60x60@2x.png",
"scale": "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
"size": "60x60",
"idiom": "iphone",
"filename": "Icon-App-60x60@3x.png",
"scale": "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
"size": "20x20",
"idiom": "ipad",
"filename": "Icon-App-20x20@1x.png",
"scale": "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"size": "20x20",
"idiom": "ipad",
"filename": "Icon-App-20x20@2x.png",
"scale": "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"size": "29x29",
"idiom": "ipad",
"filename": "Icon-App-29x29@1x.png",
"scale": "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"size": "29x29",
"idiom": "ipad",
"filename": "Icon-App-29x29@2x.png",
"scale": "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
"size": "40x40",
"idiom": "ipad",
"filename": "Icon-App-40x40@1x.png",
"scale": "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"size": "40x40",
"idiom": "ipad",
"filename": "Icon-App-40x40@2x.png",
"scale": "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
"size": "76x76",
"idiom": "ipad",
"filename": "Icon-App-76x76@1x.png",
"scale": "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
"size": "76x76",
"idiom": "ipad",
"filename": "Icon-App-76x76@2x.png",
"scale": "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
"size": "83.5x83.5",
"idiom": "ipad",
"filename": "Icon-App-83.5x83.5@2x.png",
"scale": "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
"size": "1024x1024",
"idiom": "ios-marketing",
"filename": "Icon-App-1024x1024@1x.png",
"scale": "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"version": 1,
"author": "xcode"
}
}
@@ -1,23 +1,23 @@
{
"images" : [
"images": [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
"idiom": "universal",
"filename": "LaunchImage.png",
"scale": "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
"idiom": "universal",
"filename": "LaunchImage@2x.png",
"scale": "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
"idiom": "universal",
"filename": "LaunchImage@3x.png",
"scale": "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"version": 1,
"author": "xcode"
}
}
@@ -2,4 +2,4 @@
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
+33 -33
View File
@@ -1,35 +1,35 @@
{
"name": "mfa_app",
"short_name": "mfa_app",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
"name": "mfa_app",
"short_name": "mfa_app",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
@@ -1,122 +1,122 @@
{
"images" : [
"images": [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"size": "20x20",
"idiom": "iphone",
"filename": "Icon-App-20x20@2x.png",
"scale": "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
"size": "20x20",
"idiom": "iphone",
"filename": "Icon-App-20x20@3x.png",
"scale": "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@1x.png",
"scale": "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@2x.png",
"scale": "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@3x.png",
"scale": "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"size": "40x40",
"idiom": "iphone",
"filename": "Icon-App-40x40@2x.png",
"scale": "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
"size": "40x40",
"idiom": "iphone",
"filename": "Icon-App-40x40@3x.png",
"scale": "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
"size": "60x60",
"idiom": "iphone",
"filename": "Icon-App-60x60@2x.png",
"scale": "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
"size": "60x60",
"idiom": "iphone",
"filename": "Icon-App-60x60@3x.png",
"scale": "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
"size": "20x20",
"idiom": "ipad",
"filename": "Icon-App-20x20@1x.png",
"scale": "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"size": "20x20",
"idiom": "ipad",
"filename": "Icon-App-20x20@2x.png",
"scale": "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"size": "29x29",
"idiom": "ipad",
"filename": "Icon-App-29x29@1x.png",
"scale": "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"size": "29x29",
"idiom": "ipad",
"filename": "Icon-App-29x29@2x.png",
"scale": "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
"size": "40x40",
"idiom": "ipad",
"filename": "Icon-App-40x40@1x.png",
"scale": "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"size": "40x40",
"idiom": "ipad",
"filename": "Icon-App-40x40@2x.png",
"scale": "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
"size": "76x76",
"idiom": "ipad",
"filename": "Icon-App-76x76@1x.png",
"scale": "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
"size": "76x76",
"idiom": "ipad",
"filename": "Icon-App-76x76@2x.png",
"scale": "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
"size": "83.5x83.5",
"idiom": "ipad",
"filename": "Icon-App-83.5x83.5@2x.png",
"scale": "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
"size": "1024x1024",
"idiom": "ios-marketing",
"filename": "Icon-App-1024x1024@1x.png",
"scale": "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"version": 1,
"author": "xcode"
}
}
@@ -1,23 +1,23 @@
{
"images" : [
"images": [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
"idiom": "universal",
"filename": "LaunchImage.png",
"scale": "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
"idiom": "universal",
"filename": "LaunchImage@2x.png",
"scale": "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
"idiom": "universal",
"filename": "LaunchImage@3x.png",
"scale": "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"version": 1,
"author": "xcode"
}
}
@@ -2,4 +2,4 @@
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
+85 -255
View File
@@ -22,15 +22,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"os": ["aix"],
"engines": {
"node": ">=12"
}
@@ -39,15 +35,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">=12"
}
@@ -56,15 +48,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">=12"
}
@@ -73,15 +61,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">=12"
}
@@ -90,15 +74,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">=12"
}
@@ -107,15 +87,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">=12"
}
@@ -124,15 +100,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"os": ["freebsd"],
"engines": {
"node": ">=12"
}
@@ -141,15 +113,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"os": ["freebsd"],
"engines": {
"node": ">=12"
}
@@ -158,15 +126,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -175,15 +139,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -192,15 +152,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -209,15 +165,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [
"loong64"
],
"cpu": ["loong64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -226,15 +178,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [
"mips64el"
],
"cpu": ["mips64el"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -243,15 +191,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -260,15 +204,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -277,15 +217,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [
"s390x"
],
"cpu": ["s390x"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -294,15 +230,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -311,15 +243,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"os": ["netbsd"],
"engines": {
"node": ">=12"
}
@@ -328,15 +256,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"os": ["openbsd"],
"engines": {
"node": ">=12"
}
@@ -345,15 +269,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"os": ["sunos"],
"engines": {
"node": ">=12"
}
@@ -362,15 +282,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">=12"
}
@@ -379,15 +295,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">=12"
}
@@ -396,15 +308,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">=12"
}
@@ -468,267 +376,191 @@
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.0.tgz",
"integrity": "sha512-qFcFto9figFLz2g25DxJ1WWL9+c91fTxnGuwhToCl8BaqDsDYMl/kOnBXAyAqkkzAWimYMSWNPWEjt+ADAHuoQ==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
"os": ["android"]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.0.tgz",
"integrity": "sha512-vqrQdusvVl7dthqNjWCL043qelBK+gv9v3ZiqdxgaJvmZyIAAXMjeGVSqZynKq69T7062T5VrVTuikKSAAVP6A==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
"os": ["android"]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.0.tgz",
"integrity": "sha512-617pd92LhdA9+wpixnzsyhVft3szYiN16aNUMzVkf2N+yAk8UXY226Bfp36LvxYTUt7MO/ycqGFjQgJ0wlMaWQ==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
"os": ["darwin"]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.0.tgz",
"integrity": "sha512-Y3b4oDoaEhCypg8ajPqigKDcpi5ZZovemQl9Edpem0uNv6UUjXv7iySBpGIUTSs2ovWOzYpfw9EbFJXF/fJHWw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
"os": ["darwin"]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.0.tgz",
"integrity": "sha512-3REQJ4f90sFIBfa0BUokiCdrV/E4uIjhkWe1bMgCkhFXbf4D8YN6C4zwJL881GM818qVYE9BO3dGwjKhpo2ABA==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
"os": ["freebsd"]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.0.tgz",
"integrity": "sha512-ZtY3Y8icbe3Cc+uQicsXG5L+CRGUfLZjW6j2gn5ikpltt3Whqjfo5mkyZ86UiuHF9Q3ZsaQeW7YswlHnN+lAcg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
"os": ["freebsd"]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.0.tgz",
"integrity": "sha512-bsPGGzfiHXMhQGuFGpmo2PyTwcrh2otL6ycSZAFTESviUoBOuxF7iBbAL5IJXc/69peXl5rAtbewBFeASZ9O0g==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.0.tgz",
"integrity": "sha512-kvyIECEhs2DrrdfQf++maCWJIQ974EI4txlz1nNSBaCdtf7i5Xf1AQCEJWOC5rEBisdaMFFnOWNLYt7KpFqy5A==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.0.tgz",
"integrity": "sha512-CFE7zDNrokaotXu+shwIrmWrFxllg79vciH4E/zeK7NitVuWEaXRzS0mFfFvyhZfn8WfVOG/1E9u8/DFEgK7WQ==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.0.tgz",
"integrity": "sha512-MctNTBlvMcIBP0t8lV/NXiUwFg9oK5F79CxLU+a3xgrdJjfBLVIEHSAjQ9+ipofN2GKaMLnFFXLltg1HEEPaGQ==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.0.tgz",
"integrity": "sha512-fBpoYwLEPivL3q368+gwn4qnYnr7GVwM6NnMo8rJ4wb0p/Y5lg88vQRRP077gf+tc25akuqd+1Sxbn9meODhwA==",
"cpu": [
"loong64"
],
"cpu": ["loong64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.0.tgz",
"integrity": "sha512-1hiHPV6dUaqIMXrIjN+vgJqtfkLpqHS1Xsg0oUfUVD98xGp1wX89PIXgDF2DWra1nxAd8dfE0Dk59MyeKaBVAw==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.0.tgz",
"integrity": "sha512-U0xcC80SMpEbvvLw92emHrNjlS3OXjAM0aVzlWfar6PR0ODWCTQtKeeB+tlAPGfZQXicv1SpWwRz9Hyzq3Jx3g==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.0.tgz",
"integrity": "sha512-VU/P/IODrNPasgZDLIFJmMiLGez+BN11DQWfTVlViJVabyF3JaeaJkP6teI8760f18BMGCQOW9gOmuzFaI1pUw==",
"cpu": [
"s390x"
],
"cpu": ["s390x"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.0.tgz",
"integrity": "sha512-laQVRvdbKmjXuFA3ZiZj7+U24FcmoPlXEi2OyLfbpY2MW1oxLt9Au8q9eHd0x6Pw/Kw4oe9gwVXWwIf2PVqblg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.0.tgz",
"integrity": "sha512-3wzKzduS7jzxqcOvy/ocU/gMR3/QrHEFLge5CD7Si9fyHuoXcidyYZ6jyx8OPYmCcGm3uKTUl+9jUSAY74Ln5A==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.0.tgz",
"integrity": "sha512-jROwnI1+wPyuv696rAFHp5+6RFhXGGwgmgSfzE8e4xfit6oLRg7GyMArVUoM3ChS045OwWr9aTnU+2c1UdBMyw==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.0.tgz",
"integrity": "sha512-duzweyup5WELhcXx5H1jokpr13i3BV9b48FMiikYAwk/MT1LrMYYk2TzenBd0jj4ivQIt58JWSxc19y4SvLP4g==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.30.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.0.tgz",
"integrity": "sha512-DYvxS0M07PvgvavMIybCOBYheyrqlui6ZQBHJs6GqduVzHSZ06TPPvlfvnYstjODHQ8UUXFwt5YE+h0jFI8kwg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@supabase/auth-js": {
"version": "2.67.3",
@@ -927,9 +759,7 @@
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
+39 -43
View File
@@ -1,29 +1,29 @@
import { createBrowserClient } from '@supabase/ssr';
import { hc } from 'hono/client';
import { useEffect, useState } from 'hono/jsx';
import { render } from 'hono/jsx/dom';
import type { AppType } from '.';
import { createBrowserClient } from '@supabase/ssr'
import { hc } from 'hono/client'
import { useEffect, useState } from 'hono/jsx'
import { render } from 'hono/jsx/dom'
import type { AppType } from '.'
const client = hc<AppType>('/');
const client = hc<AppType>('/')
const supabase = createBrowserClient(
import.meta.env.VITE_SUPABASE_URL!,
import.meta.env.VITE_SUPABASE_ANON_KEY!
);
)
function App() {
const [user, setUser] = useState<null | { id: string }>(null);
const [user, setUser] = useState<null | { id: string }>(null)
// Check client-side if user is logged in:
useEffect(() => {
supabase.auth.onAuthStateChange((event, session) => {
console.log('Auth event:', event);
console.log('Auth event:', event)
if (event === 'SIGNED_OUT') {
setUser(null);
setUser(null)
} else {
setUser(session?.user!);
setUser(session?.user!)
}
});
}, []);
})
}, [])
return (
<>
@@ -35,7 +35,7 @@ function App() {
<button
type="button"
onClick={() => {
window.location.href = '/signout';
window.location.href = '/signout'
}}
>
Sign out!
@@ -44,12 +44,10 @@ function App() {
<h2>Example of API fetch()</h2>
<UserDetailsButton />
<h2>Example of database read</h2>
<p>
Note that only authenticated users are able to read from the database!
</p>
<p>Note that only authenticated users are able to read from the database!</p>
<a href="/countries">Get countries</a>
</>
);
)
}
function SignIn() {
@@ -57,48 +55,46 @@ function SignIn() {
<>
<p>
Ready about and enable{' '}
<a
href="https://supabase.com/docs/guides/auth/auth-anonymous"
target="_blank"
>
<a href="https://supabase.com/docs/guides/auth/auth-anonymous" target="_blank">
anonymous signins here!
</a>
</p>
<button
type="button"
onClick={async () => {
const { data, error } = await supabase.auth.signInAnonymously();
if (error) return console.error('Error signing in:', error.message);
console.log('Signed in client-side!');
alert('Signed in anonymously! User id: ' + data?.user?.id);
const { data, error } = await supabase.auth.signInAnonymously()
if (error) return console.error('Error signing in:', error.message)
console.log('Signed in client-side!')
alert('Signed in anonymously! User id: ' + data?.user?.id)
}}
>
Anonymous sign in
</button>
</>
);
)
}
const UserDetailsButton = () => {
const [response, setResponse] = useState<string | null>(null);
const [response, setResponse] = useState<string | null>(null)
const handleClick = async () => {
const response = await client.api.user.$get();
const data = await response.json();
const headers = Array.from(response.headers.entries()).reduce<
Record<string, string>
>((acc, [key, value]) => {
acc[key] = value;
return acc;
}, {});
const response = await client.api.user.$get()
const data = await response.json()
const headers = Array.from(response.headers.entries()).reduce<Record<string, string>>(
(acc, [key, value]) => {
acc[key] = value
return acc
},
{}
)
const fullResponse = {
url: response.url,
status: response.status,
headers,
body: data,
};
setResponse(JSON.stringify(fullResponse, null, 2));
};
}
setResponse(JSON.stringify(fullResponse, null, 2))
}
return (
<div>
@@ -107,8 +103,8 @@ const UserDetailsButton = () => {
</button>
{response && <pre>{response}</pre>}
</div>
);
};
)
}
const root = document.getElementById('root')!;
render(<App />, root);
const root = document.getElementById('root')!
render(<App />, root)
+25 -28
View File
@@ -1,42 +1,42 @@
import { Hono } from 'hono';
import { getSupabase, supabaseMiddleware } from './middleware/auth.middleware';
import { Hono } from 'hono'
import { getSupabase, supabaseMiddleware } from './middleware/auth.middleware'
const app = new Hono();
app.use('*', supabaseMiddleware());
const app = new Hono()
app.use('*', supabaseMiddleware())
const routes = app.get('/api/user', async (c) => {
const supabase = getSupabase(c);
const { data, error } = await supabase.auth.getUser();
const supabase = getSupabase(c)
const { data, error } = await supabase.auth.getUser()
if (error) console.log('error', error);
if (error) console.log('error', error)
if (!data?.user) {
return c.json({
message: 'You are not logged in.',
});
})
}
return c.json({
message: 'You are logged in!',
userId: data.user,
});
});
})
})
app.get('/signout', async (c) => {
const supabase = getSupabase(c);
await supabase.auth.signOut();
console.log('Signed out server-side!');
return c.redirect('/');
});
const supabase = getSupabase(c)
await supabase.auth.signOut()
console.log('Signed out server-side!')
return c.redirect('/')
})
app.get('/countries', async (c) => {
const supabase = getSupabase(c);
const { data, error } = await supabase.from('countries').select('*');
if (error) console.log(error);
return c.json(data);
});
const supabase = getSupabase(c)
const { data, error } = await supabase.from('countries').select('*')
if (error) console.log(error)
return c.json(data)
})
export type AppType = typeof routes;
export type AppType = typeof routes
app.get('/', (c) => {
return c.html(
@@ -44,10 +44,7 @@ app.get('/', (c) => {
<head>
<meta charSet="utf-8" />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<link
rel="stylesheet"
href="https://cdn.simplecss.org/simple.min.css"
/>
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css" />
{import.meta.env.PROD ? (
<script type="module" src="/static/client.js" />
) : (
@@ -58,7 +55,7 @@ app.get('/', (c) => {
<div id="root" />
</body>
</html>
);
});
)
})
export default app;
export default app
@@ -1,56 +1,52 @@
import { createServerClient, parseCookieHeader } from '@supabase/ssr';
import { SupabaseClient } from '@supabase/supabase-js';
import type { Context, MiddlewareHandler } from 'hono';
import { env } from 'hono/adapter';
import { setCookie } from 'hono/cookie';
import { createServerClient, parseCookieHeader } from '@supabase/ssr'
import { SupabaseClient } from '@supabase/supabase-js'
import type { Context, MiddlewareHandler } from 'hono'
import { env } from 'hono/adapter'
import { setCookie } from 'hono/cookie'
declare module 'hono' {
interface ContextVariableMap {
supabase: SupabaseClient;
supabase: SupabaseClient
}
}
export const getSupabase = (c: Context) => {
return c.get('supabase');
};
return c.get('supabase')
}
type SupabaseEnv = {
VITE_SUPABASE_URL: string;
VITE_SUPABASE_ANON_KEY: string;
};
VITE_SUPABASE_URL: string
VITE_SUPABASE_ANON_KEY: string
}
export const supabaseMiddleware = (): MiddlewareHandler => {
return async (c, next) => {
const supabaseEnv = env<SupabaseEnv>(c);
const supabaseUrl =
supabaseEnv.VITE_SUPABASE_URL ?? import.meta.env.VITE_SUPABASE_URL;
const supabaseEnv = env<SupabaseEnv>(c)
const supabaseUrl = supabaseEnv.VITE_SUPABASE_URL ?? import.meta.env.VITE_SUPABASE_URL
const supabasePublishableKey =
supabaseEnv.VITE_SUPABASE_ANON_KEY ??
import.meta.env.VITE_SUPABASE_ANON_KEY;
supabaseEnv.VITE_SUPABASE_ANON_KEY ?? import.meta.env.VITE_SUPABASE_ANON_KEY
if (!supabaseUrl) {
throw new Error('SUPABASE_URL missing!');
throw new Error('SUPABASE_URL missing!')
}
if (!supabasePublishableKey) {
throw new Error('SUPABASE_ANON_KEY missing!');
throw new Error('SUPABASE_ANON_KEY missing!')
}
const supabase = createServerClient(supabaseUrl, supabasePublishableKey, {
cookies: {
getAll() {
return parseCookieHeader(c.req.header('Cookie') ?? '');
return parseCookieHeader(c.req.header('Cookie') ?? '')
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
setCookie(c, name, value, options)
);
cookiesToSet.forEach(({ name, value, options }) => setCookie(c, name, value, options))
},
},
});
})
c.set('supabase', supabase);
c.set('supabase', supabase)
await next();
};
};
await next()
}
}
+10 -10
View File
@@ -1,12 +1,12 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["@cloudflare/workers-types", "vite/client"],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
}
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["@cloudflare/workers-types", "vite/client"],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
}
}
+12 -12
View File
@@ -1,33 +1,33 @@
import devServer from "@hono/vite-dev-server";
import { defineConfig } from "vite";
import devServer from '@hono/vite-dev-server'
import { defineConfig } from 'vite'
// Change the import to use your runtime specific build
import build from "@hono/vite-build/node";
import build from '@hono/vite-build/node'
export default defineConfig(({ mode }) => {
if (mode === "client")
if (mode === 'client')
return {
esbuild: {
jsxImportSource: "hono/jsx/dom", // Optimized for hono/jsx/dom
jsxImportSource: 'hono/jsx/dom', // Optimized for hono/jsx/dom
},
build: {
rollupOptions: {
input: "./src/client.tsx",
input: './src/client.tsx',
output: {
entryFileNames: "static/client.js",
entryFileNames: 'static/client.js',
},
},
},
};
}
return {
plugins: [
build({
entry: "src/index.tsx",
entry: 'src/index.tsx',
}),
devServer({
entry: "src/index.tsx",
entry: 'src/index.tsx',
}),
],
};
});
}
})
+1 -1
View File
@@ -37,4 +37,4 @@ app.get('/countries', async (c) => {
return c.json(data)
})
export default app
export default app
@@ -48,4 +48,4 @@ export const supabaseMiddleware = (): MiddlewareHandler => {
await next()
}
}
}
+9 -15
View File
@@ -1,28 +1,22 @@
import { GeistSans } from "geist/font/sans";
import "./globals.css";
import { GeistSans } from 'geist/font/sans'
import './globals.css'
const defaultUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: "http://localhost:3000";
: 'http://localhost:3000'
export const metadata = {
metadataBase: new URL(defaultUrl),
title: "Next.js and Supabase Starter Kit",
description: "The fastest way to build apps with Next.js and Supabase",
};
title: 'Next.js and Supabase Starter Kit',
description: 'The fastest way to build apps with Next.js and Supabase',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={GeistSans.className}>
<body className="bg-background text-foreground">
<main className="min-h-screen flex flex-col items-center">
{children}
</main>
<main className="min-h-screen flex flex-col items-center">{children}</main>
</body>
</html>
);
)
}
+4 -4
View File
@@ -1,6 +1,6 @@
import Link from "next/link"
import { SubmitButton } from "./submit-button"
import { signIn, signUp } from "./actions"
import Link from 'next/link'
import { SubmitButton } from './submit-button'
import { signIn, signUp } from './actions'
export default function Login({ searchParams }: { searchParams: { message: string } }) {
return (
@@ -22,7 +22,7 @@ export default function Login({ searchParams }: { searchParams: { message: strin
className="mr-2 h-4 w-4 transition-transform group-hover:-translate-x-1"
>
<polyline points="15 18 9 12 15 6" />
</svg>{" "}
</svg>{' '}
Back
</Link>
@@ -1,20 +1,20 @@
"use client";
'use client'
import { useFormStatus } from "react-dom";
import { type ComponentProps } from "react";
import { useFormStatus } from 'react-dom'
import { type ComponentProps } from 'react'
type Props = ComponentProps<"button"> & {
pendingText?: string;
};
type Props = ComponentProps<'button'> & {
pendingText?: string
}
export function SubmitButton({ children, pendingText, ...props }: Props) {
const { pending, action } = useFormStatus();
const { pending, action } = useFormStatus()
const isPending = pending && action === props.formAction;
const isPending = pending && action === props.formAction
return (
<button {...props} type="submit" aria-disabled={pending}>
{isPending ? pendingText : children}
</button>
);
)
}
+13 -13
View File
@@ -1,23 +1,23 @@
import DeployButton from "../components/DeployButton";
import AuthButton from "../components/AuthButton";
import { createClient } from "@/lib/supabase/server";
import ConnectSupabaseSteps from "@/components/tutorial/ConnectSupabaseSteps";
import SignUpUserSteps from "@/components/tutorial/SignUpUserSteps";
import Header from "@/components/Header";
import DeployButton from '../components/DeployButton'
import AuthButton from '../components/AuthButton'
import { createClient } from '@/lib/supabase/server'
import ConnectSupabaseSteps from '@/components/tutorial/ConnectSupabaseSteps'
import SignUpUserSteps from '@/components/tutorial/SignUpUserSteps'
import Header from '@/components/Header'
export default async function Index() {
const canInitSupabaseClient = () => {
// This function is just for the interactive tutorial.
// Feel free to remove it once you have Supabase connected.
try {
createClient();
return true;
createClient()
return true
} catch (e) {
return false;
return false
}
};
}
const isSupabaseConnected = canInitSupabaseClient();
const isSupabaseConnected = canInitSupabaseClient()
return (
<div className="flex-1 w-full flex flex-col gap-20 items-center">
@@ -38,7 +38,7 @@ export default async function Index() {
<footer className="w-full border-t border-t-foreground/10 p-8 flex justify-center text-center text-xs">
<p>
Powered by{" "}
Powered by{' '}
<a
href="https://supabase.com/?utm_source=create-next-app&utm_medium=template&utm_term=nextjs"
target="_blank"
@@ -50,5 +50,5 @@ export default async function Index() {
</p>
</footer>
</div>
);
)
}
@@ -6,18 +6,10 @@ export default function DeployButton() {
target="_blank"
rel="noreferrer"
>
<svg
aria-label="Vercel logomark"
role="img"
viewBox="0 0 74 64"
className="h-4 w-4 mr-2"
>
<path
d="M37.5896 0.25L74.5396 64.25H0.639648L37.5896 0.25Z"
fill="currentColor"
></path>
<svg aria-label="Vercel logomark" role="img" viewBox="0 0 74 64" className="h-4 w-4 mr-2">
<path d="M37.5896 0.25L74.5396 64.25H0.639648L37.5896 0.25Z" fill="currentColor"></path>
</svg>
Deploy to Vercel
</a>
);
)
}
@@ -1,5 +1,5 @@
import NextLogo from "./NextLogo";
import SupabaseLogo from "./SupabaseLogo";
import NextLogo from './NextLogo'
import SupabaseLogo from './SupabaseLogo'
export default function Header() {
return (
@@ -19,7 +19,7 @@ export default function Header() {
</div>
<h1 className="sr-only">Supabase and Next.js Starter Template</h1>
<p className="text-3xl lg:text-4xl !leading-tight mx-auto max-w-xl text-center">
The fastest way to build apps with{" "}
The fastest way to build apps with{' '}
<a
href="https://supabase.com/?utm_source=create-next-app&utm_medium=template&utm_term=nextjs"
target="_blank"
@@ -27,8 +27,8 @@ export default function Header() {
rel="noreferrer"
>
Supabase
</a>{" "}
and{" "}
</a>{' '}
and{' '}
<a
href="https://nextjs.org/"
target="_blank"
@@ -40,5 +40,5 @@ export default function Header() {
</p>
<div className="w-full p-[1px] bg-gradient-to-r from-transparent via-foreground/10 to-transparent my-8" />
</div>
);
)
}
@@ -1,12 +1,6 @@
export default function NextLogo() {
return (
<svg
aria-label="Next.js logotype"
height="68"
role="img"
viewBox="0 0 394 79"
width="100"
>
<svg aria-label="Next.js logotype" height="68" role="img" viewBox="0 0 394 79" width="100">
<path
d="M261.919 0.0330722H330.547V12.7H303.323V79.339H289.71V12.7H261.919V0.0330722Z"
fill="currentColor"
@@ -42,5 +36,5 @@ export default function NextLogo() {
fill="currentColor"
/>
</svg>
);
)
}
@@ -98,5 +98,5 @@ export default function SupabaseLogo() {
</clipPath>
</defs>
</svg>
);
)
}
@@ -1,6 +1,6 @@
"use client";
'use client'
import { useState } from "react";
import { useState } from 'react'
const CopyIcon = () => (
<svg
@@ -17,7 +17,7 @@ const CopyIcon = () => (
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
);
)
const CheckIcon = () => (
<svg
@@ -33,16 +33,16 @@ const CheckIcon = () => (
>
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
);
)
export default function Code({ code }: { code: string }) {
const [icon, setIcon] = useState(CopyIcon);
const [icon, setIcon] = useState(CopyIcon)
const copy = async () => {
await navigator?.clipboard?.writeText(code);
setIcon(CheckIcon);
setTimeout(() => setIcon(CopyIcon), 2000);
};
await navigator?.clipboard?.writeText(code)
setIcon(CheckIcon)
setTimeout(() => setIcon(CopyIcon), 2000)
}
return (
<pre className="bg-foreground/5 rounded-md p-8 my-8 relative">
@@ -54,5 +54,5 @@ export default function Code({ code }: { code: string }) {
</button>
<code>{code}</code>
</pre>
);
)
}
@@ -1,11 +1,11 @@
import Step from "./Step";
import Step from './Step'
export default function ConnectSupabaseSteps() {
return (
<ol className="flex flex-col gap-6">
<Step title="Create Supabase project">
<p>
Head over to{" "}
Head over to{' '}
<a
href="https://app.supabase.com/project/_/settings/api"
target="_blank"
@@ -13,22 +13,22 @@ export default function ConnectSupabaseSteps() {
rel="noreferrer"
>
database.new
</a>{" "}
</a>{' '}
and create a new Supabase project.
</p>
</Step>
<Step title="Declare environment variables">
<p>
Rename the{" "}
Rename the{' '}
<span className="px-2 py-1 rounded-md bg-foreground/20 text-foreground/80">
.env.example
</span>{" "}
file in your Next.js app to{" "}
</span>{' '}
file in your Next.js app to{' '}
<span className="px-2 py-1 rounded-md bg-foreground/20 text-foreground/80">
.env.local
</span>{" "}
and populate with values from{" "}
</span>{' '}
and populate with values from{' '}
<a
href="https://app.supabase.com/project/_/settings/api"
target="_blank"
@@ -43,20 +43,17 @@ export default function ConnectSupabaseSteps() {
<Step title="Restart your Next.js development server">
<p>
You may need to quit your Next.js development server and run{" "}
You may need to quit your Next.js development server and run{' '}
<span className="px-2 py-1 rounded-md bg-foreground/20 text-foreground/80">
npm run dev
</span>{" "}
</span>{' '}
again to load the new environment variables.
</p>
</Step>
<Step title="Refresh the page">
<p>
You may need to refresh the page for Next.js to load the new
environment variables.
</p>
<p>You may need to refresh the page for Next.js to load the new environment variables.</p>
</Step>
</ol>
);
)
}
@@ -1,22 +1,19 @@
import Link from "next/link";
import Step from "./Step";
import Link from 'next/link'
import Step from './Step'
export default function SignUpUserSteps() {
return (
<ol className="flex flex-col gap-6">
<Step title="Sign up your first user">
<p>
Head over to the{" "}
<Link
href="/login"
className="font-bold hover:underline text-foreground/80"
>
Head over to the{' '}
<Link href="/login" className="font-bold hover:underline text-foreground/80">
Login
</Link>{" "}
page and sign up your first user. It's okay if this is just you for
now. Your awesome idea will have plenty of users later!
</Link>{' '}
page and sign up your first user. It's okay if this is just you for now. Your awesome idea
will have plenty of users later!
</p>
</Step>
</ol>
);
)
}
@@ -1,10 +1,4 @@
export default function Step({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) {
export default function Step({ title, children }: { title: string; children: React.ReactNode }) {
return (
<li className="mx-4">
<input type="checkbox" id={title} className={`mr-2 peer`} />
@@ -14,11 +8,7 @@ export default function Step({
>
{title}
</label>
<div
className={`mx-6 text-foreground/80 text-sm peer-checked:line-through`}
>
{children}
</div>
<div className={`mx-6 text-foreground/80 text-sm peer-checked:line-through`}>{children}</div>
</li>
);
)
}
@@ -5,4 +5,4 @@ export function createClient() {
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
}
}
@@ -21,7 +21,9 @@ export async function updateSession(request: NextRequest) {
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) => supabaseResponse.cookies.set(name, value, options))
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
@@ -14,7 +14,9 @@ export async function createClient() {
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options))
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// The `setAll` method was called from a Server Component.
// This can be ignored if you have proxy refreshing
+2 -2
View File
@@ -1,4 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
const nextConfig = {}
module.exports = nextConfig;
module.exports = nextConfig
+64 -192
View File
@@ -59,14 +59,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -81,14 +77,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -103,14 +95,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -119,14 +107,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -135,14 +119,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -151,14 +131,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -167,14 +143,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
"integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -183,14 +155,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -199,14 +167,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
"integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
"cpu": [
"s390x"
],
"cpu": ["s390x"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -215,14 +179,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -231,14 +191,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -247,14 +203,10 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"funding": {
"url": "https://opencollective.com/libvips"
}
@@ -263,14 +215,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -285,14 +233,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -307,14 +251,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
"integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -329,14 +269,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -351,14 +287,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
"integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
"cpu": [
"s390x"
],
"cpu": ["s390x"],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -373,14 +305,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -395,14 +323,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -417,14 +341,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -439,9 +359,7 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
"integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
"cpu": [
"wasm32"
],
"cpu": ["wasm32"],
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
@@ -458,14 +376,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -477,14 +391,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
"integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -496,14 +406,10 @@
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
@@ -556,14 +462,10 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.5.tgz",
"integrity": "sha512-65Mfo1rD+mVbJuBTlXbNelNOJ5ef+5pskifpFHsUt3cnOWjDNKctHBwwSz9tJlPp7qADZtiN/sdcG7mnc0El8Q==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">= 10"
}
@@ -572,14 +474,10 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.5.tgz",
"integrity": "sha512-2fDzXD/JpEjY500VUF0uuGq3YZcpC6XxmGabePPLyHCKbw/YXRugv3MRHH7MxE2hVHtryXeSYYnxcESb/3OUIQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">= 10"
}
@@ -588,14 +486,10 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.5.tgz",
"integrity": "sha512-meSLB52fw4tgDpPnyuhwA280EWLwwIntrxLYjzKU3e3730ur2WJAmmqoZ1LPIZ2l3eDfh9SBHnJGTczbgPeNeA==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 10"
}
@@ -604,14 +498,10 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.5.tgz",
"integrity": "sha512-aAJtQkvUzz5t0xVAmK931SIhWnSQAaEoTyG/sKPCYq2u835K/E4a14A+WRPd4dkhxIHNudE8dI+FpHekgdrA4g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 10"
}
@@ -620,14 +510,10 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.5.tgz",
"integrity": "sha512-bYwbjBwooMWRhy6vRxenaYdguTM2hlxFt1QBnUF235zTnU2DhGpETm5WU93UvtAy0uhC5Kgqsl8RyNXlprFJ6Q==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 10"
}
@@ -636,14 +522,10 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.5.tgz",
"integrity": "sha512-iGv2K/4gW3mkzh+VcZTf2gEGX5o9xdb5oPqHjgZvHdVzCw0iSAJ7n9vKzl3SIEIIHZmqRsgNasgoLd0cxaD+tg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 10"
}
@@ -652,14 +534,10 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.5.tgz",
"integrity": "sha512-6xf52Hp4SH9+4jbYmfUleqkuxvdB9JJRwwFlVG38UDuEGPqpIA+0KiJEU9lxvb0RGNo2i2ZUhc5LHajij9H9+A==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">= 10"
}
@@ -668,14 +546,10 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.5.tgz",
"integrity": "sha512-06kTaOh+Qy/kguN+MMK+/VtKmRkQJrPlGQMvCUbABk1UxI5SKTgJhbmMj9Hf0qWwrS6g9JM6/Zk+etqeMyvHAw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">= 10"
}
@@ -1232,9 +1106,7 @@
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
+1 -1
View File
@@ -3,4 +3,4 @@ module.exports = {
tailwindcss: {},
autoprefixer: {},
},
};
}
+3 -3
View File
@@ -1,5 +1,5 @@
import { type NextRequest } from "next/server"
import { updateSession } from "@/lib/supabase/proxy"
import { type NextRequest } from 'next/server'
import { updateSession } from '@/lib/supabase/proxy'
export async function proxy(request: NextRequest) {
return await updateSession(request)
@@ -14,6 +14,6 @@ export const config = {
* - favicon.ico (favicon file)
* Feel free to modify this pattern to include more paths.
*/
"/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
}
+6 -9
View File
@@ -1,20 +1,17 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
],
content: ['./app/**/*.{js,ts,jsx,tsx,mdx}', './components/**/*.{js,ts,jsx,tsx,mdx}'],
theme: {
extend: {
colors: {
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
btn: {
background: "hsl(var(--btn-background))",
"background-hover": "hsl(var(--btn-background-hover))",
background: 'hsl(var(--btn-background))',
'background-hover': 'hsl(var(--btn-background-hover))',
},
},
},
},
plugins: [],
};
}
+3 -11
View File
@@ -1,11 +1,7 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -24,9 +20,7 @@
}
],
"paths": {
"@/*": [
"./*"
]
"@/*": ["./*"]
}
},
"include": [
@@ -36,7 +30,5 @@
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
"exclude": ["node_modules"]
}
+1 -1
View File
@@ -5,4 +5,4 @@ export function createClient() {
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
}
}
+3 -1
View File
@@ -21,7 +21,9 @@ export async function updateSession(request: NextRequest) {
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) => supabaseResponse.cookies.set(name, value, options))
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
+3 -1
View File
@@ -14,7 +14,9 @@ export async function createClient() {
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options))
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// The `setAll` method was called from a Server Component.
// This can be ignored if you have middleware refreshing
+3 -3
View File
@@ -1,5 +1,5 @@
import { type NextRequest } from "next/server"
import { updateSession } from "@/lib/supabase/proxy"
import { type NextRequest } from 'next/server'
import { updateSession } from '@/lib/supabase/proxy'
export async function proxy(request: NextRequest) {
return await updateSession(request)
@@ -14,6 +14,6 @@ export const config = {
* - favicon.ico (favicon file)
* Feel free to modify this pattern to include more paths.
*/
"/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
}
@@ -1,17 +1,18 @@
import { Tabs } from 'expo-router';
import { Tabs } from 'expo-router'
import { Colors } from '@/constants/theme';
import { useColorScheme } from '@/hooks/use-color-scheme';
import { Colors } from '@/constants/theme'
import { useColorScheme } from '@/hooks/use-color-scheme'
export default function TabLayout() {
const colorScheme = useColorScheme();
const colorScheme = useColorScheme()
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
headerShown: false,
}}>
}}
>
<Tabs.Screen
name="index"
options={{
@@ -19,5 +20,5 @@ export default function TabLayout() {
}}
/>
</Tabs>
);
)
}
@@ -1,8 +1,8 @@
import { Link, Stack } from 'expo-router';
import { StyleSheet } from 'react-native';
import { Link, Stack } from 'expo-router'
import { StyleSheet } from 'react-native'
import { ThemedText } from '@/components/themed-text';
import { ThemedView } from '@/components/themed-view';
import { ThemedText } from '@/components/themed-text'
import { ThemedView } from '@/components/themed-view'
export default function NotFoundScreen() {
return (
@@ -15,7 +15,7 @@ export default function NotFoundScreen() {
</Link>
</ThemedView>
</>
);
)
}
const styles = StyleSheet.create({
@@ -29,4 +29,4 @@ const styles = StyleSheet.create({
marginTop: 15,
paddingVertical: 15,
},
});
})
@@ -1,34 +1,34 @@
import { useEffect } from 'react';
import { StyleSheet } from 'react-native';
import { useEffect } from 'react'
import { StyleSheet } from 'react-native'
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
withRepeat,
withSequence,
} from 'react-native-reanimated';
} from 'react-native-reanimated'
import { ThemedText } from '@/components/themed-text';
import { ThemedText } from '@/components/themed-text'
export function HelloWave() {
const rotationAnimation = useSharedValue(0);
const rotationAnimation = useSharedValue(0)
useEffect(() => {
rotationAnimation.value = withRepeat(
withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })),
4
);
}, [rotationAnimation]);
)
}, [rotationAnimation])
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ rotate: `${rotationAnimation.value}deg` }],
}));
}))
return (
<Animated.View style={animatedStyle}>
<ThemedText style={styles.text}>👋</ThemedText>
</Animated.View>
);
)
}
const styles = StyleSheet.create({
@@ -37,4 +37,4 @@ const styles = StyleSheet.create({
lineHeight: 32,
marginTop: -6,
},
});
})
@@ -1,30 +1,30 @@
import type { PropsWithChildren, ReactElement } from 'react';
import { StyleSheet } from 'react-native';
import type { PropsWithChildren, ReactElement } from 'react'
import { StyleSheet } from 'react-native'
import Animated, {
interpolate,
useAnimatedRef,
useAnimatedStyle,
useScrollViewOffset,
} from 'react-native-reanimated';
} from 'react-native-reanimated'
import { ThemedView } from '@/components/themed-view';
import { useColorScheme } from '@/hooks/use-color-scheme';
import { ThemedView } from '@/components/themed-view'
import { useColorScheme } from '@/hooks/use-color-scheme'
const HEADER_HEIGHT = 250;
const HEADER_HEIGHT = 250
type Props = PropsWithChildren<{
headerImage: ReactElement;
headerBackgroundColor: { dark: string; light: string };
}>;
headerImage: ReactElement
headerBackgroundColor: { dark: string; light: string }
}>
export default function ParallaxScrollView({
children,
headerImage,
headerBackgroundColor,
}: Props) {
const colorScheme = useColorScheme() ?? 'light';
const scrollRef = useAnimatedRef<Animated.ScrollView>();
const scrollOffset = useScrollViewOffset(scrollRef);
const colorScheme = useColorScheme() ?? 'light'
const scrollRef = useAnimatedRef<Animated.ScrollView>()
const scrollOffset = useScrollViewOffset(scrollRef)
const headerAnimatedStyle = useAnimatedStyle(() => {
return {
@@ -40,8 +40,8 @@ export default function ParallaxScrollView({
scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]),
},
],
};
});
}
})
return (
<ThemedView style={styles.container}>
@@ -51,13 +51,14 @@ export default function ParallaxScrollView({
styles.header,
{ backgroundColor: headerBackgroundColor[colorScheme] },
headerAnimatedStyle,
]}>
]}
>
{headerImage}
</Animated.View>
<ThemedView style={styles.content}>{children}</ThemedView>
</Animated.ScrollView>
</ThemedView>
);
)
}
const styles = StyleSheet.create({
@@ -74,4 +75,4 @@ const styles = StyleSheet.create({
gap: 16,
overflow: 'hidden',
},
});
})
@@ -1,14 +1,14 @@
import { supabase } from '@/lib/supabase';
import { appleAuthAndroid, AppleButton } from '@invertase/react-native-apple-authentication';
import { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { Platform } from 'react-native';
import 'react-native-get-random-values';
import { v4 as uuid } from 'uuid';
import { supabase } from '@/lib/supabase'
import { appleAuthAndroid, AppleButton } from '@invertase/react-native-apple-authentication'
import { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { Platform } from 'react-native'
import 'react-native-get-random-values'
import { v4 as uuid } from 'uuid'
async function onAppleButtonPress() {
// Generate secure, random values for state and nonce
const rawNonce = uuid();
const state = uuid();
const rawNonce = uuid()
const state = uuid()
// Configure the request
appleAuthAndroid.configure({
@@ -30,11 +30,11 @@ async function onAppleButtonPress() {
// Unique state value used to prevent CSRF attacks. A UUID will be generated if nothing is provided.
state,
});
})
// Open the browser window for user sign in
const credentialState = await appleAuthAndroid.signIn();
console.log('Apple sign in successful:', credentialState);
const credentialState = await appleAuthAndroid.signIn()
console.log('Apple sign in successful:', credentialState)
if (credentialState.id_token && credentialState.code && credentialState.nonce) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
@@ -42,26 +42,30 @@ async function onAppleButtonPress() {
token: credentialState.id_token,
nonce: credentialState.nonce,
access_token: credentialState.code,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials);
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Apple:', error);
console.error('Error signing in with Apple:', error)
}
if (data) {
console.log('Apple sign in successful:', data);
console.log('Apple sign in successful:', data)
}
}
}
export default function AppleSignInButton() {
if (Platform.OS !== 'android' || appleAuthAndroid.isSupported !== true) { return <></> }
if (Platform.OS !== 'android' || appleAuthAndroid.isSupported !== true) {
return <></>
}
return <AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
onPress={() => onAppleButtonPress()}
/>;
return (
<AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
onPress={() => onAppleButtonPress()}
/>
)
}
@@ -1,8 +1,8 @@
import { supabase } from '@/lib/supabase';
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication';
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { router } from 'expo-router';
import { Platform } from 'react-native';
import { supabase } from '@/lib/supabase'
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication'
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { router } from 'expo-router'
import { Platform } from 'react-native'
async function onAppleButtonPress() {
// Performs login request
@@ -10,42 +10,50 @@ async function onAppleButtonPress() {
requestedOperation: appleAuth.Operation.LOGIN,
// Note: it appears putting FULL_NAME first is important, see issue #293
requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL],
});
})
// Get the current authentication state for user
// Note: This method must be tested on a real device. On the iOS simulator it always throws an error.
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user)
console.log('Apple sign in successful:', { credentialState, appleAuthRequestResponse });
console.log('Apple sign in successful:', { credentialState, appleAuthRequestResponse })
if (credentialState === appleAuth.State.AUTHORIZED && appleAuthRequestResponse.identityToken && appleAuthRequestResponse.authorizationCode) {
if (
credentialState === appleAuth.State.AUTHORIZED &&
appleAuthRequestResponse.identityToken &&
appleAuthRequestResponse.authorizationCode
) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
provider: 'apple',
token: appleAuthRequestResponse.identityToken,
nonce: appleAuthRequestResponse.nonce,
access_token: appleAuthRequestResponse.authorizationCode,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials);
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Apple:', error);
console.error('Error signing in with Apple:', error)
}
if (data) {
console.log('Apple sign in successful:', data);
router.navigate('/(tabs)');
console.log('Apple sign in successful:', data)
router.navigate('/(tabs)')
}
}
}
export default function AppleSignInButton() {
if (Platform.OS !== 'ios') { return <></>; }
if (Platform.OS !== 'ios') {
return <></>
}
return <AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
style={{ width: 160, height: 45 }}
onPress={() => onAppleButtonPress()}
/>;
return (
<AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
style={{ width: 160, height: 45 }}
onPress={() => onAppleButtonPress()}
/>
)
}
@@ -1,8 +1,8 @@
import { supabase } from '@/lib/supabase';
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication';
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { router } from 'expo-router';
import { Platform } from 'react-native';
import { supabase } from '@/lib/supabase'
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication'
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { router } from 'expo-router'
import { Platform } from 'react-native'
async function onAppleButtonPress() {
// Performs login request
@@ -10,42 +10,50 @@ async function onAppleButtonPress() {
requestedOperation: appleAuth.Operation.LOGIN,
// Note: it appears putting FULL_NAME first is important, see issue #293
requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL],
});
})
// Get the current authentication state for user
// Note: This method must be tested on a real device. On the iOS simulator it always throws an error.
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user)
console.log('Apple sign in successful:', { credentialState, appleAuthRequestResponse });
console.log('Apple sign in successful:', { credentialState, appleAuthRequestResponse })
if (credentialState === appleAuth.State.AUTHORIZED && appleAuthRequestResponse.identityToken && appleAuthRequestResponse.authorizationCode) {
if (
credentialState === appleAuth.State.AUTHORIZED &&
appleAuthRequestResponse.identityToken &&
appleAuthRequestResponse.authorizationCode
) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
provider: 'apple',
token: appleAuthRequestResponse.identityToken,
nonce: appleAuthRequestResponse.nonce,
access_token: appleAuthRequestResponse.authorizationCode,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials);
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Apple:', error);
console.error('Error signing in with Apple:', error)
}
if (data) {
console.log('Apple sign in successful:', data);
router.navigate('/(tabs)');
console.log('Apple sign in successful:', data)
router.navigate('/(tabs)')
}
}
}
export default function AppleSignInButton() {
if (Platform.OS !== 'ios') { return <></>; }
if (Platform.OS !== 'ios') {
return <></>
}
return <AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
style={{ width: 160, height: 45 }}
onPress={() => onAppleButtonPress()}
/>;
return (
<AppleButton
buttonStyle={AppleButton.Style.BLACK}
buttonType={AppleButton.Type.SIGN_IN}
style={{ width: 160, height: 45 }}
onPress={() => onAppleButtonPress()}
/>
)
}
@@ -1,68 +1,77 @@
import { supabase } from '@/lib/supabase';
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { useEffect, useState } from 'react';
import AppleSignin, { type AppleAuthResponse } from 'react-apple-signin-auth';
import { Platform } from 'react-native';
import { supabase } from '@/lib/supabase'
import type { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { useEffect, useState } from 'react'
import AppleSignin, { type AppleAuthResponse } from 'react-apple-signin-auth'
import { Platform } from 'react-native'
export default function AppleSignInButton() {
const [nonce, setNonce] = useState('');
const [sha256Nonce, setSha256Nonce] = useState('');
const [nonce, setNonce] = useState('')
const [sha256Nonce, setSha256Nonce] = useState('')
async function onAppleButtonSuccess(appleAuthRequestResponse: AppleAuthResponse) {
console.debug('Apple sign in successful:', { appleAuthRequestResponse });
if (appleAuthRequestResponse.authorization && appleAuthRequestResponse.authorization.id_token && appleAuthRequestResponse.authorization.code) {
console.debug('Apple sign in successful:', { appleAuthRequestResponse })
if (
appleAuthRequestResponse.authorization &&
appleAuthRequestResponse.authorization.id_token &&
appleAuthRequestResponse.authorization.code
) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
provider: 'apple',
token: appleAuthRequestResponse.authorization.id_token,
nonce,
access_token: appleAuthRequestResponse.authorization.code,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Apple:', error);
console.error('Error signing in with Apple:', error)
}
if (data) {
console.log('Apple sign in successful:', data);
console.log('Apple sign in successful:', data)
}
};
}
}
useEffect(() => {
function generateNonce(): string {
const array = new Uint32Array(1);
window.crypto.getRandomValues(array);
return array[0].toString();
};
async function generateSha256Nonce(nonce: string): Promise<string> {
const buffer = await window.crypto.subtle.digest('sha-256', new TextEncoder().encode(nonce));
const array = Array.from(new Uint8Array(buffer));
return array.map(b => b.toString(16).padStart(2, '0')).join('');
const array = new Uint32Array(1)
window.crypto.getRandomValues(array)
return array[0].toString()
}
let nonce = generateNonce();
setNonce(nonce);
async function generateSha256Nonce(nonce: string): Promise<string> {
const buffer = await window.crypto.subtle.digest('sha-256', new TextEncoder().encode(nonce))
const array = Array.from(new Uint8Array(buffer))
return array.map((b) => b.toString(16).padStart(2, '0')).join('')
}
generateSha256Nonce(nonce)
.then((sha256Nonce) => { setSha256Nonce(sha256Nonce) });
}, []);
let nonce = generateNonce()
setNonce(nonce)
if (Platform.OS !== 'web') { return <></>; }
generateSha256Nonce(nonce).then((sha256Nonce) => {
setSha256Nonce(sha256Nonce)
})
}, [])
return <AppleSignin
authOptions={{
clientId: process.env.EXPO_PUBLIC_APPLE_AUTH_SERVICE_ID ?? '',
redirectURI: process.env.EXPO_PUBLIC_APPLE_AUTH_REDIRECT_URI ?? '',
scope: 'email name',
state: 'state',
nonce: sha256Nonce,
usePopup: true,
}}
uiType="dark"
onSuccess={onAppleButtonSuccess}
onError={(error: any) => console.error('Apple sign in error:', error)}
/>;
if (Platform.OS !== 'web') {
return <></>
}
return (
<AppleSignin
authOptions={{
clientId: process.env.EXPO_PUBLIC_APPLE_AUTH_SERVICE_ID ?? '',
redirectURI: process.env.EXPO_PUBLIC_APPLE_AUTH_REDIRECT_URI ?? '',
scope: 'email name',
state: 'state',
nonce: sha256Nonce,
usePopup: true,
}}
uiType="dark"
onSuccess={onAppleButtonSuccess}
onError={(error: any) => console.error('Apple sign in error:', error)}
/>
)
}
@@ -1,90 +1,89 @@
import { supabase } from '@/lib/supabase';
import { useEffect } from 'react';
import { TouchableOpacity } from 'react-native';
import { supabase } from '@/lib/supabase'
import { useEffect } from 'react'
import { TouchableOpacity } from 'react-native'
import { expo } from '@/app.json';
import { Text } from '@react-navigation/elements';
import { Image } from 'expo-image';
import * as WebBrowser from "expo-web-browser";
import { expo } from '@/app.json'
import { Text } from '@react-navigation/elements'
import { Image } from 'expo-image'
import * as WebBrowser from 'expo-web-browser'
WebBrowser.maybeCompleteAuthSession();
WebBrowser.maybeCompleteAuthSession()
export default function GoogleSignInButton() {
function extractParamsFromUrl(url: string) {
const parsedUrl = new URL(url);
const hash = parsedUrl.hash.substring(1); // Remove the leading '#'
const params = new URLSearchParams(hash);
const parsedUrl = new URL(url)
const hash = parsedUrl.hash.substring(1) // Remove the leading '#'
const params = new URLSearchParams(hash)
return {
access_token: params.get("access_token"),
expires_in: parseInt(params.get("expires_in") || "0"),
refresh_token: params.get("refresh_token"),
token_type: params.get("token_type"),
provider_token: params.get("provider_token"),
code: params.get("code"),
};
};
access_token: params.get('access_token'),
expires_in: parseInt(params.get('expires_in') || '0'),
refresh_token: params.get('refresh_token'),
token_type: params.get('token_type'),
provider_token: params.get('provider_token'),
code: params.get('code'),
}
}
async function onSignInButtonPress() {
console.debug('onSignInButtonPress - start');
console.debug('onSignInButtonPress - start')
const res = await supabase.auth.signInWithOAuth({
provider: "google",
provider: 'google',
options: {
redirectTo: `${expo.scheme}://google-auth`,
queryParams: { prompt: "consent" },
queryParams: { prompt: 'consent' },
skipBrowserRedirect: true,
},
});
})
const googleOAuthUrl = res.data.url;
const googleOAuthUrl = res.data.url
if (!googleOAuthUrl) {
console.error("no oauth url found!");
return;
console.error('no oauth url found!')
return
}
const result = await WebBrowser.openAuthSessionAsync(
googleOAuthUrl,
`${expo.scheme}://google-auth`,
{ showInRecents: true },
{ showInRecents: true }
).catch((err) => {
console.error('onSignInButtonPress - openAuthSessionAsync - error', { err });
console.log(err);
});
console.error('onSignInButtonPress - openAuthSessionAsync - error', { err })
console.log(err)
})
console.debug('onSignInButtonPress - openAuthSessionAsync - result', { result });
console.debug('onSignInButtonPress - openAuthSessionAsync - result', { result })
if (result && result.type === "success") {
console.debug('onSignInButtonPress - openAuthSessionAsync - success');
const params = extractParamsFromUrl(result.url);
console.debug('onSignInButtonPress - openAuthSessionAsync - success', { params });
if (result && result.type === 'success') {
console.debug('onSignInButtonPress - openAuthSessionAsync - success')
const params = extractParamsFromUrl(result.url)
console.debug('onSignInButtonPress - openAuthSessionAsync - success', { params })
if (params.access_token && params.refresh_token) {
console.debug('onSignInButtonPress - setSession');
console.debug('onSignInButtonPress - setSession')
const { data, error } = await supabase.auth.setSession({
access_token: params.access_token,
refresh_token: params.refresh_token,
});
console.debug('onSignInButtonPress - setSession - success', { data, error });
return;
})
console.debug('onSignInButtonPress - setSession - success', { data, error })
return
} else {
console.error('onSignInButtonPress - setSession - failed');
console.error('onSignInButtonPress - setSession - failed')
// sign in/up failed
}
} else {
console.error('onSignInButtonPress - openAuthSessionAsync - failed');
console.error('onSignInButtonPress - openAuthSessionAsync - failed')
}
}
// to warm up the browser
useEffect(() => {
WebBrowser.warmUpAsync();
WebBrowser.warmUpAsync()
return () => {
WebBrowser.coolDownAsync();
};
}, []);
WebBrowser.coolDownAsync()
}
}, [])
return (
<TouchableOpacity
@@ -122,5 +121,5 @@ export default function GoogleSignInButton() {
Sign in with Google
</Text>
</TouchableOpacity>
);
)
}
@@ -1,60 +1,60 @@
import { supabase } from '@/lib/supabase';
import { CredentialResponse, GoogleLogin, GoogleOAuthProvider } from '@react-oauth/google';
import { SignInWithIdTokenCredentials } from '@supabase/supabase-js';
import { useEffect, useState } from 'react';
import { supabase } from '@/lib/supabase'
import { CredentialResponse, GoogleLogin, GoogleOAuthProvider } from '@react-oauth/google'
import { SignInWithIdTokenCredentials } from '@supabase/supabase-js'
import { useEffect, useState } from 'react'
import 'react-native-get-random-values';
import 'react-native-get-random-values'
export default function GoogleSignInButton() {
// Generate secure, random values for state and nonce
const [nonce, setNonce] = useState('');
const [sha256Nonce, setSha256Nonce] = useState('');
const [nonce, setNonce] = useState('')
const [sha256Nonce, setSha256Nonce] = useState('')
async function onGoogleButtonSuccess(authRequestResponse: CredentialResponse) {
console.debug('Google sign in successful:', { authRequestResponse });
console.debug('Google sign in successful:', { authRequestResponse })
if (authRequestResponse.clientId && authRequestResponse.credential) {
const signInWithIdTokenCredentials: SignInWithIdTokenCredentials = {
provider: 'google',
token: authRequestResponse.credential,
nonce: nonce,
};
}
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials);
const { data, error } = await supabase.auth.signInWithIdToken(signInWithIdTokenCredentials)
if (error) {
console.error('Error signing in with Google:', error);
console.error('Error signing in with Google:', error)
}
if (data) {
console.log('Google sign in successful:', data);
console.log('Google sign in successful:', data)
}
}
}
function onGoogleButtonFailure() {
console.error('Error signing in with Google');
console.error('Error signing in with Google')
}
useEffect(() => {
function generateNonce(): string {
const array = new Uint32Array(1);
window.crypto.getRandomValues(array);
return array[0].toString();
const array = new Uint32Array(1)
window.crypto.getRandomValues(array)
return array[0].toString()
}
async function generateSha256Nonce(nonce: string): Promise<string> {
const buffer = await window.crypto.subtle.digest('sha-256', new TextEncoder().encode(nonce));
const array = Array.from(new Uint8Array(buffer));
return array.map(b => b.toString(16).padStart(2, '0')).join('');
const buffer = await window.crypto.subtle.digest('sha-256', new TextEncoder().encode(nonce))
const array = Array.from(new Uint8Array(buffer))
return array.map((b) => b.toString(16).padStart(2, '0')).join('')
}
let nonce = generateNonce();
setNonce(nonce);
let nonce = generateNonce()
setNonce(nonce)
generateSha256Nonce(nonce)
.then((sha256Nonce) => { setSha256Nonce(sha256Nonce) });
}, []);
generateSha256Nonce(nonce).then((sha256Nonce) => {
setSha256Nonce(sha256Nonce)
})
}, [])
return (
<GoogleOAuthProvider
@@ -69,5 +69,5 @@ export default function GoogleSignInButton() {
auto_select={true}
/>
</GoogleOAuthProvider>
);
)
}
@@ -1,13 +1,13 @@
import { Text, type TextProps, StyleSheet } from 'react-native';
import { Text, type TextProps, StyleSheet } from 'react-native'
import { useThemeColor } from '@/hooks/use-theme-color';
import { Fonts } from '@/constants/theme';
import { useThemeColor } from '@/hooks/use-theme-color'
import { Fonts } from '@/constants/theme'
export type ThemedTextProps = TextProps & {
lightColor?: string;
darkColor?: string;
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
};
lightColor?: string
darkColor?: string
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'
}
export function ThemedText({
style,
@@ -16,7 +16,7 @@ export function ThemedText({
type = 'default',
...rest
}: ThemedTextProps) {
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text')
return (
<Text
@@ -31,7 +31,7 @@ export function ThemedText({
]}
{...rest}
/>
);
)
}
const styles = StyleSheet.create({
@@ -58,4 +58,4 @@ const styles = StyleSheet.create({
fontSize: 16,
color: '#0a7ea4',
},
});
})
@@ -1,14 +1,14 @@
import { View, type ViewProps } from 'react-native';
import { View, type ViewProps } from 'react-native'
import { useThemeColor } from '@/hooks/use-theme-color';
import { useThemeColor } from '@/hooks/use-theme-color'
export type ThemedViewProps = ViewProps & {
lightColor?: string;
darkColor?: string;
};
lightColor?: string
darkColor?: string
}
export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background')
return <View style={[{ backgroundColor }, style]} {...otherProps} />;
return <View style={[{ backgroundColor }, style]} {...otherProps} />
}
@@ -3,10 +3,10 @@
* There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
*/
import { Platform } from 'react-native';
import { Platform } from 'react-native'
const tintColorLight = '#0a7ea4';
const tintColorDark = '#fff';
const tintColorLight = '#0a7ea4'
const tintColorDark = '#fff'
export const Colors = {
light: {
@@ -25,7 +25,7 @@ export const Colors = {
tabIconDefault: '#9BA1A6',
tabIconSelected: tintColorDark,
},
};
}
export const Fonts = Platform.select({
ios: {
@@ -50,4 +50,4 @@ export const Fonts = Platform.select({
rounded: "'SF Pro Rounded', 'Hiragino Maru Gothic ProN', Meiryo, 'MS PGothic', sans-serif",
mono: "SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
},
});
})
@@ -1,10 +1,10 @@
// https://docs.expo.dev/guides/using-eslint/
const { defineConfig } = require('eslint/config');
const expoConfig = require('eslint-config-expo/flat');
const { defineConfig } = require('eslint/config')
const expoConfig = require('eslint-config-expo/flat')
module.exports = defineConfig([
expoConfig,
{
ignores: ['dist/*'],
},
]);
])
@@ -1 +1 @@
export { useColorScheme } from 'react-native';
export { useColorScheme } from 'react-native'
@@ -1,21 +1,21 @@
import { useEffect, useState } from 'react';
import { useColorScheme as useRNColorScheme } from 'react-native';
import { useEffect, useState } from 'react'
import { useColorScheme as useRNColorScheme } from 'react-native'
/**
* To support static rendering, this value needs to be re-calculated on the client side for web
*/
export function useColorScheme() {
const [hasHydrated, setHasHydrated] = useState(false);
const [hasHydrated, setHasHydrated] = useState(false)
useEffect(() => {
setHasHydrated(true);
}, []);
setHasHydrated(true)
}, [])
const colorScheme = useRNColorScheme();
const colorScheme = useRNColorScheme()
if (hasHydrated) {
return colorScheme;
return colorScheme
}
return 'light';
return 'light'
}
@@ -3,19 +3,19 @@
* https://docs.expo.dev/guides/color-schemes/
*/
import { Colors } from '@/constants/theme';
import { useColorScheme } from '@/hooks/use-color-scheme';
import { Colors } from '@/constants/theme'
import { useColorScheme } from '@/hooks/use-color-scheme'
export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
) {
const theme = useColorScheme() ?? 'light';
const colorFromProps = props[theme];
const theme = useColorScheme() ?? 'light'
const colorFromProps = props[theme]
if (colorFromProps) {
return colorFromProps;
return colorFromProps
} else {
return Colors[theme][colorName];
return Colors[theme][colorName]
}
}
@@ -1,21 +1,23 @@
import { createClient } from '@supabase/supabase-js';
import { deleteItemAsync, getItemAsync, setItemAsync } from 'expo-secure-store';
import { createClient } from '@supabase/supabase-js'
import { deleteItemAsync, getItemAsync, setItemAsync } from 'expo-secure-store'
const ExpoSecureStoreAdapter = {
getItem: (key: string) => {
console.debug("getItem", { key, getItemAsync })
console.debug('getItem', { key, getItemAsync })
return getItemAsync(key)
},
setItem: (key: string, value: string) => {
if (value.length > 2048) {
console.warn('Value being stored in SecureStore is larger than 2048 bytes and it may not be stored successfully. In a future SDK version, this call may throw an error.')
console.warn(
'Value being stored in SecureStore is larger than 2048 bytes and it may not be stored successfully. In a future SDK version, this call may throw an error.'
)
}
return setItemAsync(key, value)
},
removeItem: (key: string) => {
return deleteItemAsync(key)
},
};
}
export const supabase = createClient(
process.env.EXPO_PUBLIC_SUPABASE_URL ?? '',
@@ -27,5 +29,5 @@ export const supabase = createClient(
persistSession: true,
detectSessionInUrl: false,
},
},
);
}
)
@@ -1,24 +1,24 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createClient } from '@supabase/supabase-js';
import 'react-native-url-polyfill/auto';
import AsyncStorage from '@react-native-async-storage/async-storage'
import { createClient } from '@supabase/supabase-js'
import 'react-native-url-polyfill/auto'
const isSSR = typeof window === 'undefined';
const isSSR = typeof window === 'undefined'
const ExpoWebSecureStoreAdapter = {
getItem: (key: string) => {
if (isSSR) return null;
console.debug("getItem", { key })
if (isSSR) return null
console.debug('getItem', { key })
return AsyncStorage.getItem(key)
},
setItem: (key: string, value: string) => {
if (isSSR) return;
if (isSSR) return
return AsyncStorage.setItem(key, value)
},
removeItem: (key: string) => {
if (isSSR) return;
if (isSSR) return
return AsyncStorage.removeItem(key)
},
};
}
export const supabase = createClient(
process.env.EXPO_PUBLIC_SUPABASE_URL ?? '',
@@ -30,5 +30,5 @@ export const supabase = createClient(
persistSession: true,
detectSessionInUrl: false,
},
},
);
}
)
@@ -3736,219 +3736,157 @@
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
"integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
"os": ["android"]
},
"node_modules/@unrs/resolver-binding-android-arm64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz",
"integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
"os": ["android"]
},
"node_modules/@unrs/resolver-binding-darwin-arm64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz",
"integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
"os": ["darwin"]
},
"node_modules/@unrs/resolver-binding-darwin-x64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz",
"integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
"os": ["darwin"]
},
"node_modules/@unrs/resolver-binding-freebsd-x64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz",
"integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
"os": ["freebsd"]
},
"node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz",
"integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz",
"integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
"integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-arm64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz",
"integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz",
"integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz",
"integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz",
"integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz",
"integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==",
"cpu": [
"s390x"
],
"cpu": ["s390x"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-x64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz",
"integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-linux-x64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz",
"integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@unrs/resolver-binding-wasm32-wasi": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz",
"integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==",
"cpu": [
"wasm32"
],
"cpu": ["wasm32"],
"dev": true,
"license": "MIT",
"optional": true,
@@ -3963,43 +3901,31 @@
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz",
"integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz",
"integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@unrs/resolver-binding-win32-x64-msvc": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz",
"integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@urql/core": {
"version": "5.2.0",
@@ -7088,9 +7014,7 @@
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
@@ -8592,14 +8516,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
"integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8612,14 +8532,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
"integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8632,14 +8548,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
"integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8652,14 +8564,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
"integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"freebsd"
],
"os": ["freebsd"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8672,14 +8580,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
"integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8692,14 +8596,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
"integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8712,14 +8612,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
"integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8732,14 +8628,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
"integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8752,14 +8644,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
"integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8772,14 +8660,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
"integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">= 12.0.0"
},
@@ -8792,14 +8676,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
"integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">= 12.0.0"
},
@@ -26,12 +26,12 @@ export default function AuthProvider({ children }: PropsWithChildren) {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(async (_event, session) => {
const { data } = session
? await supabase.auth.getClaims(session.access_token)
: { data: null }
setClaims(data?.claims ?? null)
})
} = supabase.auth.onAuthStateChange(async (_event, session) => {
const { data } = session
? await supabase.auth.getClaims(session.access_token)
: { data: null }
setClaims(data?.claims ?? null)
})
// Cleanup subscription on unmount
return () => {
@@ -45,11 +45,7 @@ export default function AuthProvider({ children }: PropsWithChildren) {
setIsLoading(true)
if (claims) {
const { data } = await supabase
.from('profiles')
.select('*')
.eq('id', claims.sub)
.single()
const { data } = await supabase.from('profiles').select('*').eq('id', claims.sub).single()
setProfile(data)
} else {
@@ -3,15 +3,8 @@
"compilerOptions": {
"strict": true,
"paths": {
"@/*": [
"./*"
]
"@/*": ["./*"]
}
},
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts"
]
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}
+23 -69
View File
@@ -4228,9 +4228,7 @@
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
@@ -4933,14 +4931,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
"integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">= 12.0.0"
},
@@ -4953,14 +4947,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
"integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">= 12.0.0"
},
@@ -4973,14 +4963,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
"integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">= 12.0.0"
},
@@ -4993,14 +4979,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
"integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"freebsd"
],
"os": ["freebsd"],
"engines": {
"node": ">= 12.0.0"
},
@@ -5013,14 +4995,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
"integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -5033,14 +5011,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
"integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -5053,14 +5027,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
"integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -5073,14 +5043,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
"integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -5093,14 +5059,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
"integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">= 12.0.0"
},
@@ -5113,14 +5075,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
"integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">= 12.0.0"
},
@@ -5133,14 +5091,10 @@
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
"integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">= 12.0.0"
},
+97 -291
View File
@@ -305,15 +305,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"os": ["aix"],
"engines": {
"node": ">=12"
}
@@ -322,15 +318,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">=12"
}
@@ -339,15 +331,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">=12"
}
@@ -356,15 +344,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"os": ["android"],
"engines": {
"node": ">=12"
}
@@ -373,15 +357,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">=12"
}
@@ -390,15 +370,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": ">=12"
}
@@ -407,15 +383,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"os": ["freebsd"],
"engines": {
"node": ">=12"
}
@@ -424,15 +396,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"os": ["freebsd"],
"engines": {
"node": ">=12"
}
@@ -441,15 +409,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -458,15 +422,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -475,15 +435,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -492,15 +448,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [
"loong64"
],
"cpu": ["loong64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -509,15 +461,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [
"mips64el"
],
"cpu": ["mips64el"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -526,15 +474,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -543,15 +487,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -560,15 +500,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [
"s390x"
],
"cpu": ["s390x"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -577,15 +513,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"os": ["linux"],
"engines": {
"node": ">=12"
}
@@ -594,15 +526,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"os": ["netbsd"],
"engines": {
"node": ">=12"
}
@@ -611,15 +539,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"os": ["openbsd"],
"engines": {
"node": ">=12"
}
@@ -628,15 +552,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"os": ["sunos"],
"engines": {
"node": ">=12"
}
@@ -645,15 +565,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">=12"
}
@@ -662,15 +578,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">=12"
}
@@ -679,15 +591,11 @@
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"os": ["win32"],
"engines": {
"node": ">=12"
}
@@ -753,351 +661,251 @@
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.0.tgz",
"integrity": "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
"os": ["android"]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.0.tgz",
"integrity": "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
"os": ["android"]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.0.tgz",
"integrity": "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
"os": ["darwin"]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.0.tgz",
"integrity": "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
"os": ["darwin"]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.0.tgz",
"integrity": "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
"os": ["freebsd"]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.0.tgz",
"integrity": "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
"os": ["freebsd"]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.0.tgz",
"integrity": "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.0.tgz",
"integrity": "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA==",
"cpu": [
"arm"
],
"cpu": ["arm"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.0.tgz",
"integrity": "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.0.tgz",
"integrity": "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.0.tgz",
"integrity": "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q==",
"cpu": [
"loong64"
],
"cpu": ["loong64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-loong64-musl": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.0.tgz",
"integrity": "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ==",
"cpu": [
"loong64"
],
"cpu": ["loong64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.0.tgz",
"integrity": "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-ppc64-musl": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.0.tgz",
"integrity": "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA==",
"cpu": [
"ppc64"
],
"cpu": ["ppc64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.0.tgz",
"integrity": "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.0.tgz",
"integrity": "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ==",
"cpu": [
"riscv64"
],
"cpu": ["riscv64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.0.tgz",
"integrity": "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg==",
"cpu": [
"s390x"
],
"cpu": ["s390x"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.0.tgz",
"integrity": "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.0.tgz",
"integrity": "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
"os": ["linux"]
},
"node_modules/@rollup/rollup-openbsd-x64": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.0.tgz",
"integrity": "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
]
"os": ["openbsd"]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.0.tgz",
"integrity": "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
]
"os": ["openharmony"]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.0.tgz",
"integrity": "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ==",
"cpu": [
"arm64"
],
"cpu": ["arm64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.0.tgz",
"integrity": "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA==",
"cpu": [
"ia32"
],
"cpu": ["ia32"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.0.tgz",
"integrity": "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.57.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.0.tgz",
"integrity": "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==",
"cpu": [
"x64"
],
"cpu": ["x64"],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
"os": ["win32"]
},
"node_modules/@supabase/auth-js": {
"version": "2.93.2",
@@ -1465,9 +1273,7 @@
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"os": ["darwin"],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
+144 -141
View File
@@ -1,155 +1,158 @@
import "./index.css";
import { useState, useEffect } from "react";
import { createClient } from "@supabase/supabase-js";
import './index.css'
import { useState, useEffect } from 'react'
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY);
const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY
)
export default function App() {
const [loading, setLoading] = useState(false);
const [email, setEmail] = useState("");
const [claims, setClaims] = useState(null);
const [loading, setLoading] = useState(false)
const [email, setEmail] = useState('')
const [claims, setClaims] = useState(null)
// Check URL params on initial render
const params = new URLSearchParams(window.location.search);
const hasTokenHash = params.get("token_hash");
// Check URL params on initial render
const params = new URLSearchParams(window.location.search)
const hasTokenHash = params.get('token_hash')
const [verifying, setVerifying] = useState(!!hasTokenHash);
const [authError, setAuthError] = useState(null);
const [authSuccess, setAuthSuccess] = useState(false);
const [verifying, setVerifying] = useState(!!hasTokenHash)
const [authError, setAuthError] = useState(null)
const [authSuccess, setAuthSuccess] = useState(false)
useEffect(() => {
// Check if we have token_hash in URL (magic link callback)
const params = new URLSearchParams(window.location.search);
const token_hash = params.get("token_hash");
const type = params.get("type");
useEffect(() => {
// Check if we have token_hash in URL (magic link callback)
const params = new URLSearchParams(window.location.search)
const token_hash = params.get('token_hash')
const type = params.get('type')
if (token_hash) {
// Verify the OTP token
supabase.auth.verifyOtp({
token_hash,
type: type || "email",
}).then(({ error }) => {
if (error) {
setAuthError(error.message);
} else {
setAuthSuccess(true);
// Clear URL params
window.history.replaceState({}, document.title, "/");
}
setVerifying(false);
});
}
// Check for existing session using getClaims
supabase.auth.getClaims().then(({ data: { claims } }) => {
setClaims(claims);
});
// Listen for auth changes
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(() => {
supabase.auth.getClaims().then(({ data: { claims } }) => {
setClaims(claims);
});
});
return () => subscription.unsubscribe();
}, []);
const handleLogin = async (event) => {
event.preventDefault();
setLoading(true);
const { error } = await supabase.auth.signInWithOtp({
email,
options: {
emailRedirectTo: window.location.origin,
}
});
if (error) {
alert(error.error_description || error.message);
} else {
alert("Check your email for the login link!");
}
setLoading(false);
};
const handleLogout = async () => {
await supabase.auth.signOut();
setClaims(null);
};
// Show verification state
if (verifying) {
return (
<div>
<h1>Authentication</h1>
<p>Confirming your magic link...</p>
<p>Loading...</p>
</div>
);
if (token_hash) {
// Verify the OTP token
supabase.auth
.verifyOtp({
token_hash,
type: type || 'email',
})
.then(({ error }) => {
if (error) {
setAuthError(error.message)
} else {
setAuthSuccess(true)
// Clear URL params
window.history.replaceState({}, document.title, '/')
}
setVerifying(false)
})
}
// Show auth error
if (authError) {
return (
<div>
<h1>Authentication</h1>
<p>✗ Authentication failed</p>
<p>{authError}</p>
<button
onClick={() => {
setAuthError(null);
window.history.replaceState({}, document.title, "/");
}}
>
Return to login
</button>
</div>
);
}
// Check for existing session using getClaims
supabase.auth.getClaims().then(({ data: { claims } }) => {
setClaims(claims)
})
// Show auth success (briefly before claims load)
if (authSuccess && !claims) {
return (
<div>
<h1>Authentication</h1>
<p>✓ Authentication successful!</p>
<p>Loading your account...</p>
</div>
);
}
// Listen for auth changes
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(() => {
supabase.auth.getClaims().then(({ data: { claims } }) => {
setClaims(claims)
})
})
// If user is logged in, show welcome screen
if (claims) {
return (
<div>
<h1>Welcome!</h1>
<p>You are logged in as: {claims.email}</p>
<button onClick={handleLogout}>
Sign Out
</button>
</div>
);
}
return () => subscription.unsubscribe()
}, [])
// Show login form
const handleLogin = async (event) => {
event.preventDefault()
setLoading(true)
const { error } = await supabase.auth.signInWithOtp({
email,
options: {
emailRedirectTo: window.location.origin,
},
})
if (error) {
alert(error.error_description || error.message)
} else {
alert('Check your email for the login link!')
}
setLoading(false)
}
const handleLogout = async () => {
await supabase.auth.signOut()
setClaims(null)
}
// Show verification state
if (verifying) {
return (
<div>
<h1>Supabase + React</h1>
<p>Sign in via magic link with your email below</p>
<form onSubmit={handleLogin}>
<input
type="email"
placeholder="Your email"
value={email}
required={true}
onChange={(e) => setEmail(e.target.value)}
/>
<button disabled={loading}>
{loading ? <span>Loading</span> : <span>Send magic link</span>}
</button>
</form>
</div>
);
<div>
<h1>Authentication</h1>
<p>Confirming your magic link...</p>
<p>Loading...</p>
</div>
)
}
// Show auth error
if (authError) {
return (
<div>
<h1>Authentication</h1>
<p>✗ Authentication failed</p>
<p>{authError}</p>
<button
onClick={() => {
setAuthError(null)
window.history.replaceState({}, document.title, '/')
}}
>
Return to login
</button>
</div>
)
}
// Show auth success (briefly before claims load)
if (authSuccess && !claims) {
return (
<div>
<h1>Authentication</h1>
<p>✓ Authentication successful!</p>
<p>Loading your account...</p>
</div>
)
}
// If user is logged in, show welcome screen
if (claims) {
return (
<div>
<h1>Welcome!</h1>
<p>You are logged in as: {claims.email}</p>
<button onClick={handleLogout}>Sign Out</button>
</div>
)
}
// Show login form
return (
<div>
<h1>Supabase + React</h1>
<p>Sign in via magic link with your email below</p>
<form onSubmit={handleLogin}>
<input
type="email"
placeholder="Your email"
value={email}
required={true}
onChange={(e) => setEmail(e.target.value)}
/>
<button disabled={loading}>
{loading ? <span>Loading</span> : <span>Send magic link</span>}
</button>
</form>
</div>
)
}
@@ -3,7 +3,9 @@
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
'Helvetica Neue', sans-serif;
background-color: #f5f5f5;
margin: 0;
padding: 20px;
+1 -1
View File
@@ -18,4 +18,4 @@ declare global {
}
}
export {}
export {}
@@ -78,4 +78,4 @@ const authGuard: Handle = async ({ event, resolve }) => {
return resolve(event)
}
export const handle: Handle = sequence(supabase, authGuard)
export const handle: Handle = sequence(supabase, authGuard)
@@ -7,4 +7,4 @@ export const load: LayoutServerLoad = async ({ locals: { safeGetSession }, cooki
user,
cookies: cookies.getAll(),
}
}
}
@@ -40,4 +40,4 @@ export const load: LayoutLoad = async ({ data, depends, fetch }) => {
} = await supabase.auth.getUser()
return { session, supabase, user }
}
}
@@ -3,4 +3,4 @@ import type { PageServerLoad } from './$types'
export const load: PageServerLoad = async ({ locals: { supabase } }) => {
const { data: colors } = await supabase.from('colors').select('name').limit(5).order('name')
return { colors: colors ?? [] }
}
}
@@ -29,4 +29,4 @@ export const actions: Actions = {
redirect(303, '/private')
}
},
}
}
@@ -28,4 +28,4 @@ export const GET: RequestHandler = async ({ url, locals: { supabase } }) => {
redirectTo.pathname = '/auth/error'
redirect(303, redirectTo)
}
}
@@ -2,4 +2,4 @@
* This file is necessary to ensure protection of all routes in the `private`
* directory. It makes the routes in this directory _dynamic_ routes, which
* send a server request, and thus trigger `hooks.server.ts`.
**/
**/
@@ -4,4 +4,4 @@ export const load: PageServerLoad = async ({ depends, locals: { supabase } }) =>
depends('supabase:db:notes')
const { data: notes } = await supabase.from('notes').select('id,note').order('id')
return { notes: notes ?? [] }
}
}
+1 -1
View File
@@ -18,4 +18,4 @@ declare global {
}
}
export {}
export {}
Loaded 100 of 343 files, more files were not shown because too many files have changed in this diff. Show more