notifications ok
This commit is contained in:
parent
9f7dabbe86
commit
823059d630
|
|
@ -3,4 +3,4 @@ EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN=
|
||||||
EXPO_PUBLIC_FIREBASE_PROJECT_ID=
|
EXPO_PUBLIC_FIREBASE_PROJECT_ID=
|
||||||
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET=
|
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET=
|
||||||
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
|
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
|
||||||
EXPO_PUBLIC_FIREBASE_APP_ID=
|
EXPO_PUBLIC_FIREBASE_APP_ID=
|
||||||
|
|
|
||||||
15
app.json
15
app.json
|
|
@ -10,7 +10,7 @@
|
||||||
"newArchEnabled": true,
|
"newArchEnabled": true,
|
||||||
"ios": {
|
"ios": {
|
||||||
"supportsTablet": true,
|
"supportsTablet": true,
|
||||||
"bundleIdentifier": "com.pierre69007.expostarter"
|
"bundleIdentifier": "com.starter.expo"
|
||||||
},
|
},
|
||||||
"android": {
|
"android": {
|
||||||
"adaptiveIcon": {
|
"adaptiveIcon": {
|
||||||
|
|
@ -21,7 +21,8 @@
|
||||||
},
|
},
|
||||||
"edgeToEdgeEnabled": true,
|
"edgeToEdgeEnabled": true,
|
||||||
"predictiveBackGestureEnabled": false,
|
"predictiveBackGestureEnabled": false,
|
||||||
"package": "com.pierre69007.expostarter"
|
"googleServicesFile": "./google-services.json",
|
||||||
|
"package": "com.starter.expo"
|
||||||
},
|
},
|
||||||
"web": {
|
"web": {
|
||||||
"output": "static",
|
"output": "static",
|
||||||
|
|
@ -29,6 +30,7 @@
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"expo-router",
|
"expo-router",
|
||||||
|
"expo-notifications",
|
||||||
[
|
[
|
||||||
"expo-splash-screen",
|
"expo-splash-screen",
|
||||||
{
|
{
|
||||||
|
|
@ -45,6 +47,13 @@
|
||||||
"experiments": {
|
"experiments": {
|
||||||
"typedRoutes": true,
|
"typedRoutes": true,
|
||||||
"reactCompiler": true
|
"reactCompiler": true
|
||||||
}
|
},
|
||||||
|
"extra": {
|
||||||
|
"router": {},
|
||||||
|
"eas": {
|
||||||
|
"projectId": "3e92de71-0ed6-43b0-903b-e020d4b110b5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"owner": "leonmorival"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||||
import { Redirect, router } from 'expo-router';
|
import { Redirect, router } from 'expo-router';
|
||||||
import { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native';
|
import { useState } from 'react';
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
Alert,
|
||||||
|
Pressable,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
import { Avatar } from '@/components/common/Avatar';
|
import { Avatar } from '@/components/common/Avatar';
|
||||||
import { Catamaran, FunnelSans } from '@/constants/fonts';
|
import { Catamaran, FunnelSans } from '@/constants/fonts';
|
||||||
import { Palette } from '@/constants/palette';
|
import { Palette } from '@/constants/palette';
|
||||||
import { Radius, Spacing } from '@/constants/styles';
|
import { Radius, Spacing } from '@/constants/styles';
|
||||||
import { useAuth } from '@/providers/AuthProvider';
|
import { useAuth } from '@/providers/AuthProvider';
|
||||||
|
import { sendTestPushNotification } from '@/services/notifications';
|
||||||
|
|
||||||
function SettingsRow({
|
function SettingsRow({
|
||||||
label,
|
label,
|
||||||
|
|
@ -34,6 +43,7 @@ function SettingsRow({
|
||||||
|
|
||||||
export default function SettingsScreen() {
|
export default function SettingsScreen() {
|
||||||
const { initializing, user } = useAuth();
|
const { initializing, user } = useAuth();
|
||||||
|
const [sendingNotification, setSendingNotification] = useState(false);
|
||||||
|
|
||||||
if (initializing) {
|
if (initializing) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -47,6 +57,28 @@ export default function SettingsScreen() {
|
||||||
return <Redirect href="/login" />;
|
return <Redirect href="/login" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const registeredPushTokens = user.expoPushTokens?.length ?? 0;
|
||||||
|
|
||||||
|
async function handleSendTestNotification() {
|
||||||
|
try {
|
||||||
|
setSendingNotification(true);
|
||||||
|
await sendTestPushNotification();
|
||||||
|
Alert.alert(
|
||||||
|
'Notification envoyee',
|
||||||
|
'Une notification push de test a ete demandee.'
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
const message =
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "Impossible d'envoyer la notification.";
|
||||||
|
|
||||||
|
Alert.alert('Erreur', message);
|
||||||
|
} finally {
|
||||||
|
setSendingNotification(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
|
|
@ -77,6 +109,30 @@ export default function SettingsScreen() {
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>Notifications</Text>
|
||||||
|
<View style={styles.sectionCard}>
|
||||||
|
<SettingsRow
|
||||||
|
description={
|
||||||
|
registeredPushTokens > 0
|
||||||
|
? `${registeredPushTokens} appareil(x) enregistre(s).`
|
||||||
|
: 'Aucun appareil enregistre pour les notifications.'
|
||||||
|
}
|
||||||
|
label="Etat des notifications"
|
||||||
|
onPress={() => undefined}
|
||||||
|
/>
|
||||||
|
<SettingsRow
|
||||||
|
description={
|
||||||
|
sendingNotification
|
||||||
|
? 'Envoi en cours...'
|
||||||
|
: 'Envoyer une notification push de test.'
|
||||||
|
}
|
||||||
|
label="Tester une notification"
|
||||||
|
onPress={handleSendTestNotification}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +195,7 @@ const styles = StyleSheet.create({
|
||||||
sectionCard: {
|
sectionCard: {
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: Palette.cream,
|
borderColor: Palette.cream,
|
||||||
borderRadius: Radius.xl,
|
borderRadius: Radius.sm,
|
||||||
backgroundColor: Palette.white,
|
backgroundColor: Palette.white,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
},
|
},
|
||||||
|
|
@ -148,7 +204,7 @@ const styles = StyleSheet.create({
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: Spacing.md,
|
gap: Spacing.md,
|
||||||
paddingHorizontal: Spacing.md,
|
paddingHorizontal: Spacing.md,
|
||||||
paddingVertical: Spacing.md,
|
paddingVertical: Spacing.sm,
|
||||||
},
|
},
|
||||||
rowContent: {
|
rowContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|
|
||||||
26
bun.lock
26
bun.lock
|
|
@ -12,10 +12,12 @@
|
||||||
"@react-navigation/native": "^7.1.8",
|
"@react-navigation/native": "^7.1.8",
|
||||||
"expo": "~54.0.33",
|
"expo": "~54.0.33",
|
||||||
"expo-constants": "~18.0.13",
|
"expo-constants": "~18.0.13",
|
||||||
|
"expo-device": "~8.0.10",
|
||||||
"expo-font": "~14.0.11",
|
"expo-font": "~14.0.11",
|
||||||
"expo-haptics": "~15.0.8",
|
"expo-haptics": "~15.0.8",
|
||||||
"expo-image": "~3.0.11",
|
"expo-image": "~3.0.11",
|
||||||
"expo-linking": "~8.0.11",
|
"expo-linking": "~8.0.11",
|
||||||
|
"expo-notifications": "~0.32.16",
|
||||||
"expo-router": "~6.0.23",
|
"expo-router": "~6.0.23",
|
||||||
"expo-splash-screen": "~31.0.13",
|
"expo-splash-screen": "~31.0.13",
|
||||||
"expo-status-bar": "~3.0.9",
|
"expo-status-bar": "~3.0.9",
|
||||||
|
|
@ -413,6 +415,8 @@
|
||||||
|
|
||||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
||||||
|
|
||||||
|
"@ide/backoff": ["@ide/backoff@1.0.0", "", {}, "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g=="],
|
||||||
|
|
||||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||||
|
|
||||||
"@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="],
|
"@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="],
|
||||||
|
|
@ -705,6 +709,8 @@
|
||||||
|
|
||||||
"asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="],
|
"asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="],
|
||||||
|
|
||||||
|
"assert": ["assert@2.1.0", "", { "dependencies": { "call-bind": "^1.0.2", "is-nan": "^1.3.2", "object-is": "^1.1.5", "object.assign": "^4.1.4", "util": "^0.12.5" } }, "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw=="],
|
||||||
|
|
||||||
"async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="],
|
"async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="],
|
||||||
|
|
||||||
"async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="],
|
"async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="],
|
||||||
|
|
@ -737,6 +743,8 @@
|
||||||
|
|
||||||
"babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="],
|
"babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="],
|
||||||
|
|
||||||
|
"badgin": ["badgin@1.2.3", "", {}, "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw=="],
|
||||||
|
|
||||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||||
|
|
||||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||||
|
|
@ -941,10 +949,14 @@
|
||||||
|
|
||||||
"expo": ["expo@54.0.33", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.23", "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/devtools": "0.1.8", "@expo/fingerprint": "0.15.4", "@expo/metro": "~54.2.0", "@expo/metro-config": "54.0.14", "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.10", "expo-asset": "~12.0.12", "expo-constants": "~18.0.13", "expo-file-system": "~19.0.21", "expo-font": "~14.0.11", "expo-keep-awake": "~15.0.8", "expo-modules-autolinking": "3.0.24", "expo-modules-core": "3.0.29", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw=="],
|
"expo": ["expo@54.0.33", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.23", "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/devtools": "0.1.8", "@expo/fingerprint": "0.15.4", "@expo/metro": "~54.2.0", "@expo/metro-config": "54.0.14", "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.10", "expo-asset": "~12.0.12", "expo-constants": "~18.0.13", "expo-file-system": "~19.0.21", "expo-font": "~14.0.11", "expo-keep-awake": "~15.0.8", "expo-modules-autolinking": "3.0.24", "expo-modules-core": "3.0.29", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw=="],
|
||||||
|
|
||||||
|
"expo-application": ["expo-application@7.0.8", "", { "peerDependencies": { "expo": "*" } }, "sha512-qFGyxk7VJbrNOQWBbE09XUuGuvkOgFS9QfToaK2FdagM2aQ+x3CvGV2DuVgl/l4ZxPgIf3b/MNh9xHpwSwn74Q=="],
|
||||||
|
|
||||||
"expo-asset": ["expo-asset@12.0.12", "", { "dependencies": { "@expo/image-utils": "^0.8.8", "expo-constants": "~18.0.12" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-CsXFCQbx2fElSMn0lyTdRIyKlSXOal6ilLJd+yeZ6xaC7I9AICQgscY5nj0QcwgA+KYYCCEQEBndMsmj7drOWQ=="],
|
"expo-asset": ["expo-asset@12.0.12", "", { "dependencies": { "@expo/image-utils": "^0.8.8", "expo-constants": "~18.0.12" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-CsXFCQbx2fElSMn0lyTdRIyKlSXOal6ilLJd+yeZ6xaC7I9AICQgscY5nj0QcwgA+KYYCCEQEBndMsmj7drOWQ=="],
|
||||||
|
|
||||||
"expo-constants": ["expo-constants@18.0.13", "", { "dependencies": { "@expo/config": "~12.0.13", "@expo/env": "~2.0.8" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ=="],
|
"expo-constants": ["expo-constants@18.0.13", "", { "dependencies": { "@expo/config": "~12.0.13", "@expo/env": "~2.0.8" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ=="],
|
||||||
|
|
||||||
|
"expo-device": ["expo-device@8.0.10", "", { "dependencies": { "ua-parser-js": "^0.7.33" }, "peerDependencies": { "expo": "*" } }, "sha512-jd5BxjaF7382JkDMaC+P04aXXknB2UhWaVx5WiQKA05ugm/8GH5uaz9P9ckWdMKZGQVVEOC8MHaUADoT26KmFA=="],
|
||||||
|
|
||||||
"expo-file-system": ["expo-file-system@19.0.21", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg=="],
|
"expo-file-system": ["expo-file-system@19.0.21", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg=="],
|
||||||
|
|
||||||
"expo-font": ["expo-font@14.0.11", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg=="],
|
"expo-font": ["expo-font@14.0.11", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg=="],
|
||||||
|
|
@ -961,6 +973,8 @@
|
||||||
|
|
||||||
"expo-modules-core": ["expo-modules-core@3.0.29", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-LzipcjGqk8gvkrOUf7O2mejNWugPkf3lmd9GkqL9WuNyeN2fRwU0Dn77e3ZUKI3k6sI+DNwjkq4Nu9fNN9WS7Q=="],
|
"expo-modules-core": ["expo-modules-core@3.0.29", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-LzipcjGqk8gvkrOUf7O2mejNWugPkf3lmd9GkqL9WuNyeN2fRwU0Dn77e3ZUKI3k6sI+DNwjkq4Nu9fNN9WS7Q=="],
|
||||||
|
|
||||||
|
"expo-notifications": ["expo-notifications@0.32.16", "", { "dependencies": { "@expo/image-utils": "^0.8.8", "@ide/backoff": "^1.0.0", "abort-controller": "^3.0.0", "assert": "^2.0.0", "badgin": "^1.1.5", "expo-application": "~7.0.8", "expo-constants": "~18.0.13" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-QQD/UA6v7LgvwIJ+tS7tSvqJZkdp0nCSj9MxsDk/jU1GttYdK49/5L2LvE/4U0H7sNBz1NZAyhDZozg8xgBLXw=="],
|
||||||
|
|
||||||
"expo-router": ["expo-router@6.0.23", "", { "dependencies": { "@expo/metro-runtime": "^6.1.2", "@expo/schema-utils": "^0.1.8", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/native": "^7.1.8", "@react-navigation/native-stack": "^7.3.16", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-server": "^1.0.5", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.1.6", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "use-latest-callback": "^0.2.1", "vaul": "^1.1.2" }, "peerDependencies": { "@react-navigation/drawer": "^7.5.0", "@testing-library/react-native": ">= 12.0.0", "expo": "*", "expo-constants": "^18.0.13", "expo-linking": "^8.0.11", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-screens": "*", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@react-navigation/drawer", "@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-qCxVAiCrCyu0npky6azEZ6dJDMt77OmCzEbpF6RbUTlfkaCA417LvY14SBkk0xyGruSxy/7pvJOI6tuThaUVCA=="],
|
"expo-router": ["expo-router@6.0.23", "", { "dependencies": { "@expo/metro-runtime": "^6.1.2", "@expo/schema-utils": "^0.1.8", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/native": "^7.1.8", "@react-navigation/native-stack": "^7.3.16", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-server": "^1.0.5", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.1.6", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "use-latest-callback": "^0.2.1", "vaul": "^1.1.2" }, "peerDependencies": { "@react-navigation/drawer": "^7.5.0", "@testing-library/react-native": ">= 12.0.0", "expo": "*", "expo-constants": "^18.0.13", "expo-linking": "^8.0.11", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-screens": "*", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@react-navigation/drawer", "@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-qCxVAiCrCyu0npky6azEZ6dJDMt77OmCzEbpF6RbUTlfkaCA417LvY14SBkk0xyGruSxy/7pvJOI6tuThaUVCA=="],
|
||||||
|
|
||||||
"expo-server": ["expo-server@1.0.5", "", {}, "sha512-IGR++flYH70rhLyeXF0Phle56/k4cee87WeQ4mamS+MkVAVP+dDlOHf2nN06Z9Y2KhU0Gp1k+y61KkghF7HdhA=="],
|
"expo-server": ["expo-server@1.0.5", "", {}, "sha512-IGR++flYH70rhLyeXF0Phle56/k4cee87WeQ4mamS+MkVAVP+dDlOHf2nN06Z9Y2KhU0Gp1k+y61KkghF7HdhA=="],
|
||||||
|
|
@ -1115,6 +1129,8 @@
|
||||||
|
|
||||||
"invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="],
|
"invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="],
|
||||||
|
|
||||||
|
"is-arguments": ["is-arguments@1.2.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA=="],
|
||||||
|
|
||||||
"is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
|
"is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
|
||||||
|
|
||||||
"is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="],
|
"is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="],
|
||||||
|
|
@ -1149,6 +1165,8 @@
|
||||||
|
|
||||||
"is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
|
"is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
|
||||||
|
|
||||||
|
"is-nan": ["is-nan@1.3.2", "", { "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" } }, "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w=="],
|
||||||
|
|
||||||
"is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="],
|
"is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="],
|
||||||
|
|
||||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||||
|
|
@ -1379,6 +1397,8 @@
|
||||||
|
|
||||||
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||||
|
|
||||||
|
"object-is": ["object-is@1.1.6", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1" } }, "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q=="],
|
||||||
|
|
||||||
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
|
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
|
||||||
|
|
||||||
"object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
|
"object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
|
||||||
|
|
@ -1713,7 +1733,7 @@
|
||||||
|
|
||||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
"ua-parser-js": ["ua-parser-js@1.0.41", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug=="],
|
"ua-parser-js": ["ua-parser-js@0.7.41", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg=="],
|
||||||
|
|
||||||
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
|
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
|
||||||
|
|
||||||
|
|
@ -1745,6 +1765,8 @@
|
||||||
|
|
||||||
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
||||||
|
|
||||||
|
"util": ["util@0.12.5", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="],
|
||||||
|
|
||||||
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
|
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
|
||||||
|
|
||||||
"uuid": ["uuid@7.0.3", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="],
|
"uuid": ["uuid@7.0.3", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="],
|
||||||
|
|
@ -1941,6 +1963,8 @@
|
||||||
|
|
||||||
"fbjs/promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="],
|
"fbjs/promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="],
|
||||||
|
|
||||||
|
"fbjs/ua-parser-js": ["ua-parser-js@1.0.41", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug=="],
|
||||||
|
|
||||||
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||||
|
|
||||||
"finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
|
"finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ const copyByMode = {
|
||||||
export function AuthForm({ mode }: AuthFormProps) {
|
export function AuthForm({ mode }: AuthFormProps) {
|
||||||
const copy = copyByMode[mode];
|
const copy = copyByMode[mode];
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('leon.morival@gmail.com');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('Furioza98*');
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"cli": {
|
||||||
|
"version": ">= 18.7.0",
|
||||||
|
"appVersionSource": "remote"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"development": {
|
||||||
|
"developmentClient": true,
|
||||||
|
"distribution": "internal"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"distribution": "internal"
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"autoIncrement": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"submit": {
|
||||||
|
"production": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,217 @@
|
||||||
|
[debug] [2026-04-19T16:48:31.474Z] ----------------------------------------------------------------------
|
||||||
|
[debug] [2026-04-19T16:48:31.476Z] Command: /usr/local/bin/firebase /home/leon/.cache/firebase/tools/lib/node_modules/firebase-tools/lib/bin/firebase emulators:start --only functions
|
||||||
|
[debug] [2026-04-19T16:48:31.476Z] CLI Version: 15.15.0
|
||||||
|
[debug] [2026-04-19T16:48:31.476Z] Platform: linux
|
||||||
|
[debug] [2026-04-19T16:48:31.476Z] Node Version: v20.18.2
|
||||||
|
[debug] [2026-04-19T16:48:31.476Z] Time: Sun Apr 19 2026 18:48:31 GMT+0200 (GMT+02:00)
|
||||||
|
[debug] [2026-04-19T16:48:31.476Z] ----------------------------------------------------------------------
|
||||||
|
[debug]
|
||||||
|
[debug] [2026-04-19T16:48:31.907Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
||||||
|
[debug] [2026-04-19T16:48:31.907Z] > authorizing via signed-in user (leon.morival@gmail.com)
|
||||||
|
[info] i emulators: Starting emulators: functions {"metadata":{"emulator":{"name":"hub"},"message":"Starting emulators: functions"}}
|
||||||
|
[debug] [2026-04-19T16:48:31.917Z] [logging] Logging Emulator only supports listening on one address (127.0.0.1). Not listening on ::1
|
||||||
|
[debug] [2026-04-19T16:48:31.917Z] assigned listening specs for emulators {"user":{"ui":[{"address":"0.0.0.0","family":"IPv4","port":4000}],"hub":[{"address":"127.0.0.1","family":"IPv4","port":4400},{"address":"::1","family":"IPv6","port":4400}],"logging":[{"address":"127.0.0.1","family":"IPv4","port":4500}]},"metadata":{"message":"assigned listening specs for emulators"}}
|
||||||
|
[debug] [2026-04-19T16:48:31.919Z] Write emulator hub locator at /tmp/hub-expo-starter-9daef.json
|
||||||
|
[debug] [2026-04-19T16:48:31.923Z] [eventarc] Eventarc Emulator only supports listening on one address (127.0.0.1). Not listening on ::1
|
||||||
|
[debug] [2026-04-19T16:48:31.923Z] [tasks] Cloud Tasks Emulator only supports listening on one address (127.0.0.1). Not listening on ::1
|
||||||
|
[debug] [2026-04-19T16:48:31.923Z] late-assigned ports for functions and eventarc emulators {"user":{"ui":[{"address":"0.0.0.0","family":"IPv4","port":4000}],"hub":[{"address":"127.0.0.1","family":"IPv4","port":4400},{"address":"::1","family":"IPv6","port":4400}],"logging":[{"address":"127.0.0.1","family":"IPv4","port":4500}],"functions":[{"address":"0.0.0.0","family":"IPv4","port":5001}],"eventarc":[{"address":"127.0.0.1","family":"IPv4","port":9299}],"tasks":[{"address":"127.0.0.1","family":"IPv4","port":9499}]},"metadata":{"message":"late-assigned ports for functions and eventarc emulators"}}
|
||||||
|
[warn] ⚠ functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: apphosting, auth, firestore, database, hosting, pubsub, storage, dataconnect {"metadata":{"emulator":{"name":"functions"},"message":"The following emulators are not running, calls to these services from the Functions emulator will affect production: \u001b[1mapphosting, auth, firestore, database, hosting, pubsub, storage, dataconnect\u001b[22m"}}
|
||||||
|
[debug] [2026-04-19T16:48:31.939Z] defaultcredentials: writing to file /home/leon/.config/firebase/leon_morival_gmail.com_application_default_credentials.json
|
||||||
|
[debug] [2026-04-19T16:48:31.940Z] Setting GAC to /home/leon/.config/firebase/leon_morival_gmail.com_application_default_credentials.json {"metadata":{"emulator":{"name":"functions"},"message":"Setting GAC to /home/leon/.config/firebase/leon_morival_gmail.com_application_default_credentials.json"}}
|
||||||
|
[debug] [2026-04-19T16:48:31.940Z] Checked if tokens are valid: true, expires at: 1776620760607
|
||||||
|
[debug] [2026-04-19T16:48:31.940Z] Checked if tokens are valid: true, expires at: 1776620760607
|
||||||
|
[debug] [2026-04-19T16:48:31.941Z] >>> [apiv2][query] GET https://firebase.googleapis.com/v1beta1/projects/expo-starter-9daef/adminSdkConfig [none]
|
||||||
|
[debug] [2026-04-19T16:48:32.358Z] <<< [apiv2][status] GET https://firebase.googleapis.com/v1beta1/projects/expo-starter-9daef/adminSdkConfig 200
|
||||||
|
[debug] [2026-04-19T16:48:32.358Z] <<< [apiv2][body] GET https://firebase.googleapis.com/v1beta1/projects/expo-starter-9daef/adminSdkConfig {"projectId":"expo-starter-9daef","storageBucket":"expo-starter-9daef.firebasestorage.app"}
|
||||||
|
[info] i functions: Watching "/home/leon/Workspace/perso/starter/expo-starter/functions" for Cloud Functions... {"metadata":{"emulator":{"name":"functions"},"message":"Watching \"/home/leon/Workspace/perso/starter/expo-starter/functions\" for Cloud Functions..."}}
|
||||||
|
[debug] [2026-04-19T16:48:32.373Z] Validating nodejs source
|
||||||
|
[debug] [2026-04-19T16:48:32.726Z] > [functions] package.json contents: {
|
||||||
|
"name": "functions",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "ESLINT_USE_FLAT_CONFIG=false eslint --ext .js,.ts src",
|
||||||
|
"build": "tsc",
|
||||||
|
"build:watch": "tsc --watch",
|
||||||
|
"serve": "npm run build && firebase emulators:start --only functions",
|
||||||
|
"shell": "npm run build && firebase functions:shell",
|
||||||
|
"start": "npm run shell",
|
||||||
|
"deploy": "firebase deploy --only functions",
|
||||||
|
"logs": "firebase functions:log"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "24"
|
||||||
|
},
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"firebase-admin": "^13.6.0",
|
||||||
|
"firebase-functions": "^7.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.12.0",
|
||||||
|
"@typescript-eslint/parser": "^5.12.0",
|
||||||
|
"eslint": "^8.9.0",
|
||||||
|
"eslint-config-google": "^0.14.0",
|
||||||
|
"eslint-plugin-import": "^2.25.4",
|
||||||
|
"firebase-functions-test": "^3.4.1",
|
||||||
|
"typescript": "^6.0.0"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
|
[debug] [2026-04-19T16:48:32.726Z] Building nodejs source
|
||||||
|
[debug] [2026-04-19T16:48:32.727Z] Failed to find version of module node: reached end of search path /home/leon/Workspace/perso/starter/expo-starter/functions/node_modules
|
||||||
|
[warn] ⚠ functions: You've requested "node" version "24", but the standalone Firebase CLI comes with bundled Node "20".
|
||||||
|
[info] ✔ functions: To use a different Node.js version, consider removing the standalone Firebase CLI and switching to "firebase-tools" on npm.
|
||||||
|
[debug] [2026-04-19T16:48:32.728Z] Could not find functions.yaml. Must use http discovery
|
||||||
|
[debug] [2026-04-19T16:48:32.730Z] Found firebase-functions binary at '/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/.bin/firebase-functions'
|
||||||
|
[info] Serving at port 8679
|
||||||
|
|
||||||
|
[debug] [2026-04-19T16:48:33.073Z] Got response from /__/functions.yaml {"endpoints":{"deleteUserAuthOnUserDocumentDeleted":{"availableMemoryMb":null,"timeoutSeconds":null,"minInstances":null,"maxInstances":10,"ingressSettings":null,"concurrency":null,"serviceAccountEmail":null,"vpc":null,"platform":"gcfv2","labels":{},"eventTrigger":{"eventType":"google.cloud.firestore.document.v1.deleted","eventFilters":{"database":"(default)","namespace":"(default)"},"eventFilterPathPatterns":{"document":"users/{uid}"},"retry":false},"entryPoint":"deleteUserAuthOnUserDocumentDeleted"},"sendTestPushNotification":{"availableMemoryMb":null,"timeoutSeconds":null,"minInstances":null,"maxInstances":10,"ingressSettings":null,"concurrency":null,"serviceAccountEmail":null,"vpc":null,"platform":"gcfv2","labels":{},"callableTrigger":{},"entryPoint":"sendTestPushNotification"}},"specVersion":"v1alpha1","requiredAPIs":[],"extensions":{}}
|
||||||
|
[debug] [2026-04-19T16:48:34.822Z] [work-queue] {"queuedWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:48:34.822Z"],"queueLength":1,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:48:34.822Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:48:34.822Z"],"workRunningCount":1}
|
||||||
|
[debug] [2026-04-19T16:48:34.823Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":[],"workRunningCount":0}
|
||||||
|
[info] ✔ functions: Loaded functions definitions from source: deleteUserAuthOnUserDocumentDeleted, sendTestPushNotification. {"metadata":{"emulator":{"name":"functions"},"message":"Loaded functions definitions from source: deleteUserAuthOnUserDocumentDeleted, sendTestPushNotification."}}
|
||||||
|
[info] i functions[us-central1-deleteUserAuthOnUserDocumentDeleted]: function ignored because the firestore emulator does not exist or is not running. {"metadata":{"emulator":{"name":"functions"},"message":"function ignored because the firestore emulator does not exist or is not running."}}
|
||||||
|
[info] ✔ functions[us-central1-sendTestPushNotification]: http function initialized (http://127.0.0.1:5001/expo-starter-9daef/us-central1/sendTestPushNotification). {"metadata":{"emulator":{"name":"functions"},"message":"\u001b[1mhttp\u001b[22m function initialized (http://127.0.0.1:5001/expo-starter-9daef/us-central1/sendTestPushNotification)."}}
|
||||||
|
[debug] [2026-04-19T16:48:37.112Z] Could not find VSCode notification endpoint: FetchError: request to http://localhost:40001/vscode/notify failed, reason: connect ECONNREFUSED 127.0.0.1:40001. If you are not running the Firebase SQL Connect VSCode extension, this is expected and not an issue.
|
||||||
|
[info]
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ ✔ All emulators ready! It is now safe to connect your app. │
|
||||||
|
│ i View Emulator UI at http://127.0.0.1:4000/ │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
┌───────────┬──────────────┬─────────────────────────────────┐
|
||||||
|
│ Emulator │ Host:Port │ View in Emulator UI │
|
||||||
|
├───────────┼──────────────┼─────────────────────────────────┤
|
||||||
|
│ Functions │ 0.0.0.0:5001 │ http://127.0.0.1:4000/functions │
|
||||||
|
└───────────┴──────────────┴─────────────────────────────────┘
|
||||||
|
Emulator Hub host: 127.0.0.1 port: 4400
|
||||||
|
Other reserved ports: 4500
|
||||||
|
|
||||||
|
Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.
|
||||||
|
|
||||||
|
[debug] [2026-04-19T16:48:40.336Z] [work-queue] {"queuedWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:48:40.336Z"],"queueLength":1,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:48:40.337Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:48:40.336Z"],"workRunningCount":1}
|
||||||
|
[debug] [2026-04-19T16:48:40.337Z] Accepted request POST /expo-starter-9daef/us-central1/sendTestPushNotification --> us-central1-sendTestPushNotification
|
||||||
|
[debug] [2026-04-19T16:48:40.338Z] [functions] Runtime ready! Sending request! {"metadata":{"emulator":{"name":"functions"},"message":"[functions] Runtime ready! Sending request!"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.339Z] [functions] Got req.url=/expo-starter-9daef/us-central1/sendTestPushNotification, mapping to path=/ {"metadata":{"emulator":{"name":"functions"},"message":"[functions] Got req.url=/expo-starter-9daef/us-central1/sendTestPushNotification, mapping to path=/"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.344Z] [worker-pool] addWorker(us-central1-sendTestPushNotification) {"metadata":{"emulator":{"name":"functions"},"message":"[worker-pool] addWorker(us-central1-sendTestPushNotification)"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.345Z] [worker-pool] Adding worker with key us-central1-sendTestPushNotification, total=1 {"metadata":{"emulator":{"name":"functions"},"message":"[worker-pool] Adding worker with key us-central1-sendTestPushNotification, total=1"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.707Z] [runtime-status] [63867] Resolved module firebase-admin {"declared":true,"installed":true,"version":"13.8.0","resolution":"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-admin/lib/index.js"} {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Resolved module firebase-admin {\"declared\":true,\"installed\":true,\"version\":\"13.8.0\",\"resolution\":\"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-admin/lib/index.js\"}"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.707Z] [runtime-status] [63867] Resolved module firebase-functions {"declared":true,"installed":true,"version":"7.2.5","resolution":"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-functions/lib/v2/index.js"} {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Resolved module firebase-functions {\"declared\":true,\"installed\":true,\"version\":\"7.2.5\",\"resolution\":\"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-functions/lib/v2/index.js\"}"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.707Z] [runtime-status] [63867] Outgoing network have been stubbed. [{"name":"http","status":"mocked"},{"name":"http","status":"mocked"},{"name":"https","status":"mocked"},{"name":"https","status":"mocked"},{"name":"net","status":"mocked"}] {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Outgoing network have been stubbed. [{\"name\":\"http\",\"status\":\"mocked\"},{\"name\":\"http\",\"status\":\"mocked\"},{\"name\":\"https\",\"status\":\"mocked\"},{\"name\":\"https\",\"status\":\"mocked\"},{\"name\":\"net\",\"status\":\"mocked\"}]"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.707Z] [runtime-status] [63867] Resolved module firebase-functions {"declared":true,"installed":true,"version":"7.2.5","resolution":"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-functions/lib/v2/index.js"} {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Resolved module firebase-functions {\"declared\":true,\"installed\":true,\"version\":\"7.2.5\",\"resolution\":\"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-functions/lib/v2/index.js\"}"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.707Z] [runtime-status] [63867] Detected firebase-functions v7+, skipping legacy stubs. {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Detected firebase-functions v7+, skipping legacy stubs."}}
|
||||||
|
[debug] [2026-04-19T16:48:40.707Z] [runtime-status] [63867] Resolved module firebase-admin {"declared":true,"installed":true,"version":"13.8.0","resolution":"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-admin/lib/index.js"} {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Resolved module firebase-admin {\"declared\":true,\"installed\":true,\"version\":\"13.8.0\",\"resolution\":\"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-admin/lib/index.js\"}"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.727Z] [runtime-status] [63867] Resolved module firebase-functions {"declared":true,"installed":true,"version":"7.2.5","resolution":"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-functions/lib/v2/index.js"} {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Resolved module firebase-functions {\"declared\":true,\"installed\":true,\"version\":\"7.2.5\",\"resolution\":\"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-functions/lib/v2/index.js\"}"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.798Z] [runtime-status] [63867] firebase-admin has been stubbed. {"adminResolution":{"declared":true,"installed":true,"version":"13.8.0","resolution":"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-admin/lib/index.js"}} {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] firebase-admin has been stubbed. {\"adminResolution\":{\"declared\":true,\"installed\":true,\"version\":\"13.8.0\",\"resolution\":\"/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/firebase-admin/lib/index.js\"}}"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.803Z] [runtime-status] [63867] Functions runtime initialized. {"cwd":"/home/leon/Workspace/perso/starter/expo-starter/functions","node_version":"20.18.2"} {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Functions runtime initialized. {\"cwd\":\"/home/leon/Workspace/perso/starter/expo-starter/functions\",\"node_version\":\"20.18.2\"}"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.803Z] [runtime-status] [63867] Listening to port: /tmp/fire_emu_5ad7eed774b9d705.sock {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[runtime-status] [63867] Listening to port: /tmp/fire_emu_5ad7eed774b9d705.sock"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.855Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE"}}
|
||||||
|
[debug] [2026-04-19T16:48:40.855Z] [worker-pool] submitRequest(triggerId=us-central1-sendTestPushNotification) {"metadata":{"emulator":{"name":"functions"},"message":"[worker-pool] submitRequest(triggerId=us-central1-sendTestPushNotification)"}}
|
||||||
|
[info] i functions: Beginning execution of "us-central1-sendTestPushNotification" {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Beginning execution of \"us-central1-sendTestPushNotification\""}}
|
||||||
|
[debug] [2026-04-19T16:48:40.856Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: BUSY {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: BUSY"}}
|
||||||
|
[info] > {"verifications":{"app":"MISSING","auth":"VALID"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"DEBUG","message":"Callable request verification passed"} {"user":{"verifications":{"app":"MISSING","auth":"VALID"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"DEBUG","message":"Callable request verification passed"},"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"\u001b[90m> \u001b[39m {\"verifications\":{\"app\":\"MISSING\",\"auth\":\"VALID\"},\"logging.googleapis.com/labels\":{\"firebase-log-type\":\"callable-request-verification\"},\"severity\":\"DEBUG\",\"message\":\"Callable request verification passed\"}"}}
|
||||||
|
[warn] ⚠ Google API requested!
|
||||||
|
- URL: "https://oauth2.googleapis.com/token"
|
||||||
|
- Be careful, this may be a production service. {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Google API requested!\n - URL: \"https://oauth2.googleapis.com/token\"\n - Be careful, this may be a production service."}}
|
||||||
|
[info] > {"uid":"O8lgsPxjejS7WZYVN1qa8wAZfiA2","response":[{"status":"error","message":"\"fn_xv7aZRAGC92nuZbTRYM:APA91bE...wLvTQTf_J3VmP7wcfgFOmXiYgYo\" is not a valid Expo push token","details":{"error":"DeviceNotRegistered","expoPushToken":"fn_xv7aZRAGC92nuZbTRYM:APA91bE...wLvTQTf_J3VmP7wcfgFOmXiYgYo"}},{"status":"error","message":"Unable to retrieve the FCM server key for the recipient's app. Make sure you have provided a server key as directed by the Expo FCM documentation.","details":{"error":"InvalidCredentials","fault":"developer"}}],"severity":"INFO","message":"Test push notification sent."} {"user":{"uid":"O8lgsPxjejS7WZYVN1qa8wAZfiA2","response":[{"status":"error","message":"\"fn_xv7aZRAGC92nuZbTRYM:APA91bE...wLvTQTf_J3VmP7wcfgFOmXiYgYo\" is not a valid Expo push token","details":{"error":"DeviceNotRegistered","expoPushToken":"fn_xv7aZRAGC92nuZbTRYM:APA91bE...wLvTQTf_J3VmP7wcfgFOmXiYgYo"}},{"status":"error","message":"Unable to retrieve the FCM server key for the recipient's app. Make sure you have provided a server key as directed by the Expo FCM documentation.","details":{"error":"InvalidCredentials","fault":"developer"}}],"severity":"INFO","message":"Test push notification sent."},"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"\u001b[90m> \u001b[39m {\"uid\":\"O8lgsPxjejS7WZYVN1qa8wAZfiA2\",\"response\":[{\"status\":\"error\",\"message\":\"\\\"fn_xv7aZRAGC92nuZbTRYM:APA91bE...wLvTQTf_J3VmP7wcfgFOmXiYgYo\\\" is not a valid Expo push token\",\"details\":{\"error\":\"DeviceNotRegistered\",\"expoPushToken\":\"fn_xv7aZRAGC92nuZbTRYM:APA91bE...wLvTQTf_J3VmP7wcfgFOmXiYgYo\"}},{\"status\":\"error\",\"message\":\"Unable to retrieve the FCM server key for the recipient's app. Make sure you have provided a server key as directed by the Expo FCM documentation.\",\"details\":{\"error\":\"InvalidCredentials\",\"fault\":\"developer\"}}],\"severity\":\"INFO\",\"message\":\"Test push notification sent.\"}"}}
|
||||||
|
[debug] [2026-04-19T16:48:41.877Z] Finishing up request with event=pause {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=pause"}}
|
||||||
|
[info] i functions: Finished "us-central1-sendTestPushNotification" in 1021.358853ms {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finished \"us-central1-sendTestPushNotification\" in 1021.358853ms"}}
|
||||||
|
[debug] [2026-04-19T16:48:41.878Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE"}}
|
||||||
|
[debug] [2026-04-19T16:48:41.878Z] Finishing up request with event=finish {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=finish"}}
|
||||||
|
[debug] [2026-04-19T16:48:41.878Z] Finishing up request with event=close {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=close"}}
|
||||||
|
[debug] [2026-04-19T16:48:41.878Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:50:23.257Z] [work-queue] {"queuedWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:50:23.257Z"],"queueLength":1,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:50:23.257Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:50:23.257Z"],"workRunningCount":1}
|
||||||
|
[debug] [2026-04-19T16:50:23.257Z] Accepted request POST /expo-starter-9daef/us-central1/sendTestPushNotification --> us-central1-sendTestPushNotification
|
||||||
|
[debug] [2026-04-19T16:50:23.258Z] [functions] Runtime ready! Sending request! {"metadata":{"emulator":{"name":"functions"},"message":"[functions] Runtime ready! Sending request!"}}
|
||||||
|
[debug] [2026-04-19T16:50:23.259Z] [functions] Got req.url=/expo-starter-9daef/us-central1/sendTestPushNotification, mapping to path=/ {"metadata":{"emulator":{"name":"functions"},"message":"[functions] Got req.url=/expo-starter-9daef/us-central1/sendTestPushNotification, mapping to path=/"}}
|
||||||
|
[debug] [2026-04-19T16:50:23.259Z] [worker-pool] submitRequest(triggerId=us-central1-sendTestPushNotification) {"metadata":{"emulator":{"name":"functions"},"message":"[worker-pool] submitRequest(triggerId=us-central1-sendTestPushNotification)"}}
|
||||||
|
[info] i functions: Beginning execution of "us-central1-sendTestPushNotification" {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Beginning execution of \"us-central1-sendTestPushNotification\""}}
|
||||||
|
[debug] [2026-04-19T16:50:23.260Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: BUSY {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: BUSY"}}
|
||||||
|
[info] > {"verifications":{"app":"MISSING","auth":"VALID"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"DEBUG","message":"Callable request verification passed"} {"user":{"verifications":{"app":"MISSING","auth":"VALID"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"DEBUG","message":"Callable request verification passed"},"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"\u001b[90m> \u001b[39m {\"verifications\":{\"app\":\"MISSING\",\"auth\":\"VALID\"},\"logging.googleapis.com/labels\":{\"firebase-log-type\":\"callable-request-verification\"},\"severity\":\"DEBUG\",\"message\":\"Callable request verification passed\"}"}}
|
||||||
|
[info] > {"uid":"O8lgsPxjejS7WZYVN1qa8wAZfiA2","response":[{"status":"error","message":"Unable to retrieve the FCM server key for the recipient's app. Make sure you have provided a server key as directed by the Expo FCM documentation.","details":{"error":"InvalidCredentials","fault":"developer"}}],"severity":"INFO","message":"Test push notification sent."} {"user":{"uid":"O8lgsPxjejS7WZYVN1qa8wAZfiA2","response":[{"status":"error","message":"Unable to retrieve the FCM server key for the recipient's app. Make sure you have provided a server key as directed by the Expo FCM documentation.","details":{"error":"InvalidCredentials","fault":"developer"}}],"severity":"INFO","message":"Test push notification sent."},"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"\u001b[90m> \u001b[39m {\"uid\":\"O8lgsPxjejS7WZYVN1qa8wAZfiA2\",\"response\":[{\"status\":\"error\",\"message\":\"Unable to retrieve the FCM server key for the recipient's app. Make sure you have provided a server key as directed by the Expo FCM documentation.\",\"details\":{\"error\":\"InvalidCredentials\",\"fault\":\"developer\"}}],\"severity\":\"INFO\",\"message\":\"Test push notification sent.\"}"}}
|
||||||
|
[debug] [2026-04-19T16:50:23.660Z] Finishing up request with event=pause {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=pause"}}
|
||||||
|
[info] i functions: Finished "us-central1-sendTestPushNotification" in 400.343794ms {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finished \"us-central1-sendTestPushNotification\" in 400.343794ms"}}
|
||||||
|
[debug] [2026-04-19T16:50:23.660Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE"}}
|
||||||
|
[debug] [2026-04-19T16:50:23.660Z] Finishing up request with event=finish {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=finish"}}
|
||||||
|
[debug] [2026-04-19T16:50:23.661Z] Finishing up request with event=close {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=close"}}
|
||||||
|
[debug] [2026-04-19T16:50:23.661Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:54:50.209Z] [work-queue] {"queuedWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:54:50.209Z"],"queueLength":1,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:54:50.209Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:54:50.209Z"],"workRunningCount":1}
|
||||||
|
[debug] [2026-04-19T16:54:50.210Z] Accepted request POST /expo-starter-9daef/us-central1/sendTestPushNotification --> us-central1-sendTestPushNotification
|
||||||
|
[debug] [2026-04-19T16:54:50.210Z] [functions] Runtime ready! Sending request! {"metadata":{"emulator":{"name":"functions"},"message":"[functions] Runtime ready! Sending request!"}}
|
||||||
|
[debug] [2026-04-19T16:54:50.211Z] [functions] Got req.url=/expo-starter-9daef/us-central1/sendTestPushNotification, mapping to path=/ {"metadata":{"emulator":{"name":"functions"},"message":"[functions] Got req.url=/expo-starter-9daef/us-central1/sendTestPushNotification, mapping to path=/"}}
|
||||||
|
[debug] [2026-04-19T16:54:50.211Z] [worker-pool] submitRequest(triggerId=us-central1-sendTestPushNotification) {"metadata":{"emulator":{"name":"functions"},"message":"[worker-pool] submitRequest(triggerId=us-central1-sendTestPushNotification)"}}
|
||||||
|
[info] i functions: Beginning execution of "us-central1-sendTestPushNotification" {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Beginning execution of \"us-central1-sendTestPushNotification\""}}
|
||||||
|
[debug] [2026-04-19T16:54:50.211Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: BUSY {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: BUSY"}}
|
||||||
|
[info] > {"verifications":{"app":"MISSING","auth":"VALID"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"DEBUG","message":"Callable request verification passed"} {"user":{"verifications":{"app":"MISSING","auth":"VALID"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"DEBUG","message":"Callable request verification passed"},"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"\u001b[90m> \u001b[39m {\"verifications\":{\"app\":\"MISSING\",\"auth\":\"VALID\"},\"logging.googleapis.com/labels\":{\"firebase-log-type\":\"callable-request-verification\"},\"severity\":\"DEBUG\",\"message\":\"Callable request verification passed\"}"}}
|
||||||
|
[info] > {"uid":"O8lgsPxjejS7WZYVN1qa8wAZfiA2","response":[{"status":"ok","id":"019da6aa-95b7-71d2-94fb-4eba9aa8650e"}],"severity":"INFO","message":"Test push notification sent."} {"user":{"uid":"O8lgsPxjejS7WZYVN1qa8wAZfiA2","response":[{"status":"ok","id":"019da6aa-95b7-71d2-94fb-4eba9aa8650e"}],"severity":"INFO","message":"Test push notification sent."},"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"\u001b[90m> \u001b[39m {\"uid\":\"O8lgsPxjejS7WZYVN1qa8wAZfiA2\",\"response\":[{\"status\":\"ok\",\"id\":\"019da6aa-95b7-71d2-94fb-4eba9aa8650e\"}],\"severity\":\"INFO\",\"message\":\"Test push notification sent.\"}"}}
|
||||||
|
[debug] [2026-04-19T16:54:50.715Z] Finishing up request with event=pause {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=pause"}}
|
||||||
|
[info] i functions: Finished "us-central1-sendTestPushNotification" in 503.61932ms {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finished \"us-central1-sendTestPushNotification\" in 503.61932ms"}}
|
||||||
|
[debug] [2026-04-19T16:54:50.715Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE"}}
|
||||||
|
[debug] [2026-04-19T16:54:50.715Z] Finishing up request with event=finish {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=finish"}}
|
||||||
|
[debug] [2026-04-19T16:54:50.715Z] Finishing up request with event=close {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=close"}}
|
||||||
|
[debug] [2026-04-19T16:54:50.715Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:55:02.329Z] [work-queue] {"queuedWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:55:02.329Z"],"queueLength":1,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:55:02.329Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":["/expo-starter-9daef/us-central1/sendTestPushNotification-2026-04-19T16:55:02.329Z"],"workRunningCount":1}
|
||||||
|
[debug] [2026-04-19T16:55:02.330Z] Accepted request POST /expo-starter-9daef/us-central1/sendTestPushNotification --> us-central1-sendTestPushNotification
|
||||||
|
[debug] [2026-04-19T16:55:02.330Z] [functions] Runtime ready! Sending request! {"metadata":{"emulator":{"name":"functions"},"message":"[functions] Runtime ready! Sending request!"}}
|
||||||
|
[debug] [2026-04-19T16:55:02.330Z] [functions] Got req.url=/expo-starter-9daef/us-central1/sendTestPushNotification, mapping to path=/ {"metadata":{"emulator":{"name":"functions"},"message":"[functions] Got req.url=/expo-starter-9daef/us-central1/sendTestPushNotification, mapping to path=/"}}
|
||||||
|
[debug] [2026-04-19T16:55:02.331Z] [worker-pool] submitRequest(triggerId=us-central1-sendTestPushNotification) {"metadata":{"emulator":{"name":"functions"},"message":"[worker-pool] submitRequest(triggerId=us-central1-sendTestPushNotification)"}}
|
||||||
|
[info] i functions: Beginning execution of "us-central1-sendTestPushNotification" {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Beginning execution of \"us-central1-sendTestPushNotification\""}}
|
||||||
|
[debug] [2026-04-19T16:55:02.331Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: BUSY {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: BUSY"}}
|
||||||
|
[info] > {"verifications":{"app":"MISSING","auth":"VALID"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"DEBUG","message":"Callable request verification passed"} {"user":{"verifications":{"app":"MISSING","auth":"VALID"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"DEBUG","message":"Callable request verification passed"},"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"\u001b[90m> \u001b[39m {\"verifications\":{\"app\":\"MISSING\",\"auth\":\"VALID\"},\"logging.googleapis.com/labels\":{\"firebase-log-type\":\"callable-request-verification\"},\"severity\":\"DEBUG\",\"message\":\"Callable request verification passed\"}"}}
|
||||||
|
[info] > {"uid":"O8lgsPxjejS7WZYVN1qa8wAZfiA2","response":[{"status":"ok","id":"019da6aa-c4a6-75d0-8e77-b9ff5b055321"}],"severity":"INFO","message":"Test push notification sent."} {"user":{"uid":"O8lgsPxjejS7WZYVN1qa8wAZfiA2","response":[{"status":"ok","id":"019da6aa-c4a6-75d0-8e77-b9ff5b055321"}],"severity":"INFO","message":"Test push notification sent."},"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"\u001b[90m> \u001b[39m {\"uid\":\"O8lgsPxjejS7WZYVN1qa8wAZfiA2\",\"response\":[{\"status\":\"ok\",\"id\":\"019da6aa-c4a6-75d0-8e77-b9ff5b055321\"}],\"severity\":\"INFO\",\"message\":\"Test push notification sent.\"}"}}
|
||||||
|
[debug] [2026-04-19T16:55:02.693Z] Finishing up request with event=pause {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=pause"}}
|
||||||
|
[info] i functions: Finished "us-central1-sendTestPushNotification" in 361.626998ms {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finished \"us-central1-sendTestPushNotification\" in 361.626998ms"}}
|
||||||
|
[debug] [2026-04-19T16:55:02.693Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: IDLE"}}
|
||||||
|
[debug] [2026-04-19T16:55:02.693Z] Finishing up request with event=finish {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=finish"}}
|
||||||
|
[debug] [2026-04-19T16:55:02.694Z] Finishing up request with event=close {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"Finishing up request with event=close"}}
|
||||||
|
[debug] [2026-04-19T16:55:02.694Z] [work-queue] {"queuedWork":[],"queueLength":0,"runningWork":[],"workRunningCount":0}
|
||||||
|
[debug] [2026-04-19T16:57:32.477Z] File /home/leon/Workspace/perso/starter/expo-starter/functions/src/notifications.ts changed, reloading triggers {"metadata":{"emulator":{"name":"functions"},"message":"File /home/leon/Workspace/perso/starter/expo-starter/functions/src/notifications.ts changed, reloading triggers"}}
|
||||||
|
[debug] [2026-04-19T16:57:33.478Z] Validating nodejs source
|
||||||
|
[debug] [2026-04-19T16:57:33.929Z] > [functions] package.json contents: {
|
||||||
|
"name": "functions",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "ESLINT_USE_FLAT_CONFIG=false eslint --ext .js,.ts src",
|
||||||
|
"build": "tsc",
|
||||||
|
"build:watch": "tsc --watch",
|
||||||
|
"serve": "npm run build && firebase emulators:start --only functions",
|
||||||
|
"shell": "npm run build && firebase functions:shell",
|
||||||
|
"start": "npm run shell",
|
||||||
|
"deploy": "firebase deploy --only functions",
|
||||||
|
"logs": "firebase functions:log"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "24"
|
||||||
|
},
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"firebase-admin": "^13.6.0",
|
||||||
|
"firebase-functions": "^7.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.12.0",
|
||||||
|
"@typescript-eslint/parser": "^5.12.0",
|
||||||
|
"eslint": "^8.9.0",
|
||||||
|
"eslint-config-google": "^0.14.0",
|
||||||
|
"eslint-plugin-import": "^2.25.4",
|
||||||
|
"firebase-functions-test": "^3.4.1",
|
||||||
|
"typescript": "^6.0.0"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
|
[debug] [2026-04-19T16:57:33.929Z] Building nodejs source
|
||||||
|
[debug] [2026-04-19T16:57:33.929Z] Failed to find version of module node: reached end of search path /home/leon/Workspace/perso/starter/expo-starter/functions/node_modules
|
||||||
|
[warn] ⚠ functions: You've requested "node" version "24", but the standalone Firebase CLI comes with bundled Node "20".
|
||||||
|
[info] ✔ functions: To use a different Node.js version, consider removing the standalone Firebase CLI and switching to "firebase-tools" on npm.
|
||||||
|
[debug] [2026-04-19T16:57:33.930Z] Could not find functions.yaml. Must use http discovery
|
||||||
|
[debug] [2026-04-19T16:57:33.930Z] Found firebase-functions binary at '/home/leon/Workspace/perso/starter/expo-starter/functions/node_modules/.bin/firebase-functions'
|
||||||
|
[info] Serving at port 8523
|
||||||
|
|
||||||
|
[debug] [2026-04-19T16:57:34.271Z] Got response from /__/functions.yaml {"endpoints":{"deleteUserAuthOnUserDocumentDeleted":{"availableMemoryMb":null,"timeoutSeconds":null,"minInstances":null,"maxInstances":10,"ingressSettings":null,"concurrency":null,"serviceAccountEmail":null,"vpc":null,"platform":"gcfv2","labels":{},"eventTrigger":{"eventType":"google.cloud.firestore.document.v1.deleted","eventFilters":{"database":"(default)","namespace":"(default)"},"eventFilterPathPatterns":{"document":"users/{uid}"},"retry":false},"entryPoint":"deleteUserAuthOnUserDocumentDeleted"},"sendTestPushNotification":{"availableMemoryMb":null,"timeoutSeconds":null,"minInstances":null,"maxInstances":10,"ingressSettings":null,"concurrency":null,"serviceAccountEmail":null,"vpc":null,"platform":"gcfv2","labels":{},"callableTrigger":{},"entryPoint":"sendTestPushNotification"}},"specVersion":"v1alpha1","requiredAPIs":[],"extensions":{}}
|
||||||
|
[info] ✔ functions: Loaded functions definitions from source: deleteUserAuthOnUserDocumentDeleted, sendTestPushNotification. {"metadata":{"emulator":{"name":"functions"},"message":"Loaded functions definitions from source: deleteUserAuthOnUserDocumentDeleted, sendTestPushNotification."}}
|
||||||
|
[debug] [2026-04-19T16:57:38.293Z] [worker-pool] Shutting down IDLE worker (us-central1-sendTestPushNotification) {"metadata":{"emulator":{"name":"functions"},"message":"[worker-pool] Shutting down IDLE worker (us-central1-sendTestPushNotification)"}}
|
||||||
|
[debug] [2026-04-19T16:57:38.293Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: FINISHING {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: FINISHING"}}
|
||||||
|
[debug] [2026-04-19T16:57:38.302Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: exited {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: exited"}}
|
||||||
|
[debug] [2026-04-19T16:57:38.302Z] [worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: FINISHED {"metadata":{"emulator":{"name":"functions"},"function":{"name":"us-central1-sendTestPushNotification"},"extension":{},"message":"[worker-us-central1-sendTestPushNotification-b55f52a6-94a7-4563-9b9b-a70f4e52f589]: FINISHED"}}
|
||||||
|
|
@ -12,5 +12,25 @@
|
||||||
"*.local"
|
"*.local"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"emulators": {
|
||||||
|
"auth": {
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 9099
|
||||||
|
},
|
||||||
|
"firestore": {
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 8080
|
||||||
|
},
|
||||||
|
"functions": {
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 5001
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"enabled": true,
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 4000
|
||||||
|
},
|
||||||
|
"singleProjectMode": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@ import {setGlobalOptions} from "firebase-functions/v2";
|
||||||
setGlobalOptions({maxInstances: 10});
|
setGlobalOptions({maxInstances: 10});
|
||||||
|
|
||||||
export * from "./users";
|
export * from "./users";
|
||||||
|
export * from "./notifications";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
import {getApps, initializeApp} from "firebase-admin/app";
|
||||||
|
import {getFirestore} from "firebase-admin/firestore";
|
||||||
|
import * as logger from "firebase-functions/logger";
|
||||||
|
import {HttpsError, onCall} from "firebase-functions/v2/https";
|
||||||
|
|
||||||
|
const adminApp = getApps().length > 0 ? getApps()[0] : initializeApp();
|
||||||
|
const db = getFirestore(adminApp);
|
||||||
|
|
||||||
|
type UserDocument = {
|
||||||
|
expoPushTokens?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type ExpoPushMessage = {
|
||||||
|
to: string;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
data?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ExpoPushResponse = {
|
||||||
|
data?: unknown;
|
||||||
|
errors?: unknown[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends one or more push notifications through the Expo Push API.
|
||||||
|
* @param {ExpoPushMessage[]} messages Notification payloads to send.
|
||||||
|
* @return {Promise<ExpoPushResponse>} Expo push API response payload.
|
||||||
|
*/
|
||||||
|
async function sendExpoPushNotification(messages: ExpoPushMessage[]) {
|
||||||
|
const response = await fetch("https://exp.host/--/api/v2/push/send", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Accept-Encoding": "gzip, deflate",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(messages),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new HttpsError(
|
||||||
|
"internal",
|
||||||
|
`Expo push API returned ${response.status}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await response.json()) as ExpoPushResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sendTestPushNotification = onCall(async (request) => {
|
||||||
|
if (!request.auth?.uid) {
|
||||||
|
throw new HttpsError("unauthenticated", "Authentication is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const userSnapshot = await db.doc(`users/${request.auth.uid}`).get();
|
||||||
|
const user = userSnapshot.data() as UserDocument | undefined;
|
||||||
|
const expoPushTokens = user?.expoPushTokens ?? [];
|
||||||
|
|
||||||
|
if (expoPushTokens.length === 0) {
|
||||||
|
throw new HttpsError(
|
||||||
|
"failed-precondition",
|
||||||
|
"No Expo push tokens found for this user."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await sendExpoPushNotification(
|
||||||
|
expoPushTokens.map((token) => ({
|
||||||
|
to: token,
|
||||||
|
title: "Notification de test",
|
||||||
|
body: "Le flux Expo Notifications est correctement configure.",
|
||||||
|
data: {
|
||||||
|
type: "test",
|
||||||
|
sentAt: new Date(),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.errors?.length) {
|
||||||
|
logger.error("Expo push API returned errors.", {errors: result.errors});
|
||||||
|
throw new HttpsError("internal", "Expo push API returned errors.");
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Test push notification sent.", {
|
||||||
|
uid: request.auth.uid,
|
||||||
|
response: result.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {success: true};
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "157599391636",
|
||||||
|
"project_id": "expo-starter-9daef",
|
||||||
|
"storage_bucket": "expo-starter-9daef.firebasestorage.app"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:157599391636:android:785115f243be601be17981",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.starter.expo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyBhAvRoINlRgpbtzDn0bJ3gGja4ZdvRvYs"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ const defaultFirebaseAuthErrorMessage =
|
||||||
|
|
||||||
export function mapFirebaseAuthError(error: unknown) {
|
export function mapFirebaseAuthError(error: unknown) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
|
console.log("error message", message)
|
||||||
for (const [code, mappedMessage] of Object.entries(firebaseAuthErrorMessages)) {
|
for (const [code, mappedMessage] of Object.entries(firebaseAuthErrorMessages)) {
|
||||||
if (message.includes(code)) {
|
if (message.includes(code)) {
|
||||||
return mappedMessage;
|
return mappedMessage;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
import { getApps, initializeApp } from 'firebase/app';
|
import { getApps, initializeApp } from 'firebase/app';
|
||||||
import { getAuth, type Auth } from 'firebase/auth';
|
import { connectAuthEmulator, getAuth, type Auth } from 'firebase/auth';
|
||||||
import { getFirestore } from 'firebase/firestore';
|
import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore';
|
||||||
|
import { connectFunctionsEmulator, getFunctions } from 'firebase/functions';
|
||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
import type { FirebaseApp } from 'firebase/app';
|
import type { FirebaseApp } from 'firebase/app';
|
||||||
|
|
||||||
|
|
@ -15,21 +16,23 @@ type ReactNativeAuthModule = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const firebaseConfig = {
|
const firebaseConfig = {
|
||||||
apiKey:
|
apiKey:
|
||||||
process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
|
process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
|
||||||
authDomain:
|
authDomain:
|
||||||
process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
||||||
projectId:
|
projectId:
|
||||||
process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
|
process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
|
||||||
storageBucket:
|
storageBucket:
|
||||||
process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET,
|
process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET,
|
||||||
messagingSenderId:
|
messagingSenderId:
|
||||||
process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
||||||
appId: process.env.EXPO_PUBLIC_FIREBASE_APP_ID,
|
appId: process.env.EXPO_PUBLIC_FIREBASE_APP_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAppInitialized = getApps().length > 0;
|
const isAppInitialized = getApps().length > 0;
|
||||||
const app = isAppInitialized ? getApps()[0] : initializeApp(firebaseConfig);
|
const app = isAppInitialized ? getApps()[0] : initializeApp(firebaseConfig);
|
||||||
|
const useFirebaseEmulators = true;
|
||||||
|
const firebaseEmulatorHost = '192.168.1.171';
|
||||||
const reactNativeAuth =
|
const reactNativeAuth =
|
||||||
Platform.OS === 'web'
|
Platform.OS === 'web'
|
||||||
? null
|
? null
|
||||||
|
|
@ -44,5 +47,20 @@ const auth =
|
||||||
persistence: (reactNativeAuth as ReactNativeAuthModule).getReactNativePersistence(AsyncStorage),
|
persistence: (reactNativeAuth as ReactNativeAuthModule).getReactNativePersistence(AsyncStorage),
|
||||||
});
|
});
|
||||||
|
|
||||||
export { auth };
|
const db = getFirestore(app);
|
||||||
export const db = getFirestore(app);
|
const functions = getFunctions(app);
|
||||||
|
|
||||||
|
if (useFirebaseEmulators ) {
|
||||||
|
console.info(
|
||||||
|
`[firebase] using local emulators on ${firebaseEmulatorHost} (auth:9099, firestore:8080, functions:5001)`
|
||||||
|
);
|
||||||
|
// connectAuthEmulator(auth, `http://${firebaseEmulatorHost}:9099`, {
|
||||||
|
// disableWarnings: true,
|
||||||
|
// });
|
||||||
|
// connectFirestoreEmulator(db, firebaseEmulatorHost, 8080);
|
||||||
|
connectFunctionsEmulator(functions, firebaseEmulatorHost, 5001);
|
||||||
|
} else {
|
||||||
|
console.info('[firebase] using production Firebase services');
|
||||||
|
}
|
||||||
|
|
||||||
|
export { auth, db, functions };
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,12 @@
|
||||||
"@react-navigation/native": "^7.1.8",
|
"@react-navigation/native": "^7.1.8",
|
||||||
"expo": "~54.0.33",
|
"expo": "~54.0.33",
|
||||||
"expo-constants": "~18.0.13",
|
"expo-constants": "~18.0.13",
|
||||||
|
"expo-device": "~8.0.10",
|
||||||
"expo-font": "~14.0.11",
|
"expo-font": "~14.0.11",
|
||||||
"expo-haptics": "~15.0.8",
|
"expo-haptics": "~15.0.8",
|
||||||
"expo-image": "~3.0.11",
|
"expo-image": "~3.0.11",
|
||||||
"expo-linking": "~8.0.11",
|
"expo-linking": "~8.0.11",
|
||||||
|
"expo-notifications": "~0.32.16",
|
||||||
"expo-router": "~6.0.23",
|
"expo-router": "~6.0.23",
|
||||||
"expo-splash-screen": "~31.0.13",
|
"expo-splash-screen": "~31.0.13",
|
||||||
"expo-status-bar": "~3.0.9",
|
"expo-status-bar": "~3.0.9",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ import { onSnapshot } from 'firebase/firestore';
|
||||||
|
|
||||||
import { auth } from '@/lib/firebase';
|
import { auth } from '@/lib/firebase';
|
||||||
import { userDoc } from '@/lib/firestore';
|
import { userDoc } from '@/lib/firestore';
|
||||||
|
import {
|
||||||
|
registerForPushNotifications,
|
||||||
|
subscribeToPushTokenRefresh,
|
||||||
|
} from '@/services/notifications';
|
||||||
import type { UserDocument } from '@/types/firestore';
|
import type { UserDocument } from '@/types/firestore';
|
||||||
|
|
||||||
type AuthContextValue = {
|
type AuthContextValue = {
|
||||||
|
|
@ -62,6 +66,20 @@ export function AuthProvider({ children }: PropsWithChildren) {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!authUser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerForPushNotifications(authUser.uid);
|
||||||
|
|
||||||
|
const unsubscribePushTokenRefresh = subscribeToPushTokenRefresh(
|
||||||
|
authUser.uid
|
||||||
|
);
|
||||||
|
|
||||||
|
return unsubscribePushTokenRefresh;
|
||||||
|
}, [authUser]);
|
||||||
|
|
||||||
const value = useMemo(
|
const value = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
authUser,
|
authUser,
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ export async function registerWithEmail({
|
||||||
email: credential.user.email ?? normalizedEmail,
|
email: credential.user.email ?? normalizedEmail,
|
||||||
username: normalizedUsername,
|
username: normalizedUsername,
|
||||||
profilePicture: credential.user.photoURL,
|
profilePicture: credential.user.photoURL,
|
||||||
|
expoPushTokens: [],
|
||||||
createdAt: serverTimestamp(),
|
createdAt: serverTimestamp(),
|
||||||
updatedAt: serverTimestamp(),
|
updatedAt: serverTimestamp(),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
import Constants from 'expo-constants';
|
||||||
|
import * as Device from 'expo-device';
|
||||||
|
import * as Notifications from 'expo-notifications';
|
||||||
|
import { httpsCallable } from 'firebase/functions';
|
||||||
|
import {
|
||||||
|
arrayUnion,
|
||||||
|
serverTimestamp,
|
||||||
|
setDoc,
|
||||||
|
} from 'firebase/firestore';
|
||||||
|
import { Platform } from 'react-native';
|
||||||
|
|
||||||
|
import { functions } from '@/lib/firebase';
|
||||||
|
import { userDocRef } from '@/lib/firestore';
|
||||||
|
|
||||||
|
Notifications.setNotificationHandler({
|
||||||
|
handleNotification: async () => ({
|
||||||
|
shouldPlaySound: false,
|
||||||
|
shouldSetBadge: false,
|
||||||
|
shouldShowBanner: true,
|
||||||
|
shouldShowList: true,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
type NotificationSettingsPayload = {
|
||||||
|
expoPushToken: string | null;
|
||||||
|
pushEnabled: boolean;
|
||||||
|
platform: 'android' | 'ios' | 'web' | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SendTestPushNotificationResult = {
|
||||||
|
success: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function saveExpoPushToken(
|
||||||
|
uid: string,
|
||||||
|
expoPushToken: string
|
||||||
|
) {
|
||||||
|
await setDoc(
|
||||||
|
userDocRef(uid),
|
||||||
|
{
|
||||||
|
expoPushTokens: arrayUnion(expoPushToken),
|
||||||
|
updatedAt: serverTimestamp(),
|
||||||
|
},
|
||||||
|
{ merge: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProjectId() {
|
||||||
|
const projectId =
|
||||||
|
Constants.expoConfig?.extra?.eas?.projectId ?? Constants.easConfig?.projectId;
|
||||||
|
|
||||||
|
if (!projectId) {
|
||||||
|
throw new Error('EAS projectId introuvable pour Expo Notifications.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function registerForPushNotifications(uid: string) {
|
||||||
|
if (Platform.OS === 'web') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Device.isDevice) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingPermissions = await Notifications.getPermissionsAsync();
|
||||||
|
let finalStatus = existingPermissions.status;
|
||||||
|
|
||||||
|
if (finalStatus !== 'granted') {
|
||||||
|
const requestedPermissions = await Notifications.requestPermissionsAsync();
|
||||||
|
finalStatus = requestedPermissions.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finalStatus !== 'granted') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const expoPushToken = (
|
||||||
|
await Notifications.getExpoPushTokenAsync({
|
||||||
|
projectId: getProjectId(),
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
|
||||||
|
await saveExpoPushToken(uid, expoPushToken);
|
||||||
|
|
||||||
|
return expoPushToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function subscribeToPushTokenRefresh(uid: string) {
|
||||||
|
if (Platform.OS === 'web') {
|
||||||
|
return () => undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscription = Notifications.addPushTokenListener((token) => {
|
||||||
|
void saveExpoPushToken(uid, token.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
subscription.remove();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendTestPushNotification() {
|
||||||
|
const callable = httpsCallable<undefined, SendTestPushNotificationResult>(
|
||||||
|
functions,
|
||||||
|
'sendTestPushNotification'
|
||||||
|
);
|
||||||
|
|
||||||
|
await callable();
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ export type UserDocument = {
|
||||||
email: string;
|
email: string;
|
||||||
username: string | null;
|
username: string | null;
|
||||||
profilePicture: string | null;
|
profilePicture: string | null;
|
||||||
|
expoPushTokens?: string[];
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
};
|
};
|
||||||
|
|
@ -14,6 +15,7 @@ export type UserFirestoreDocument = {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
username: string | null;
|
username: string | null;
|
||||||
profilePicture: string | null;
|
profilePicture: string | null;
|
||||||
|
expoPushTokens?: string[];
|
||||||
createdAt: Timestamp;
|
createdAt: Timestamp;
|
||||||
updatedAt: Timestamp;
|
updatedAt: Timestamp;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue