From 98fa6d35275632e13d946c3e85b8a3f2357c812c Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Tue, 18 Aug 2026 13:22:38 +0530 Subject: [PATCH 01/12] refactor: password item card --- src/app/(tabs)/(password-manager)/index.tsx | 69 ++++---------------- src/components/PasswordItemCard.tsx | 72 +++++++++++++++++++++ 2 files changed, 85 insertions(+), 56 deletions(-) create mode 100644 src/components/PasswordItemCard.tsx diff --git a/src/app/(tabs)/(password-manager)/index.tsx b/src/app/(tabs)/(password-manager)/index.tsx index 970a82a3..c3abcc2e 100644 --- a/src/app/(tabs)/(password-manager)/index.tsx +++ b/src/app/(tabs)/(password-manager)/index.tsx @@ -1,6 +1,6 @@ +import PasswordItemCard from "@/components/PasswordItemCard"; import Text from "@/components/Text"; import { passwords } from "@/db/schema"; -import formatDate from "@/utils/formating"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; import { FlashList } from "@shopify/flash-list"; import { eq } from "drizzle-orm"; @@ -8,7 +8,7 @@ import { drizzle, useLiveQuery } from "drizzle-orm/expo-sqlite"; import { router, Stack } from "expo-router"; import { useSQLiteContext } from "expo-sqlite"; import { useMemo, useState } from "react"; -import { Alert, Pressable, StyleSheet, View } from "react-native"; +import { Alert, Pressable } from "react-native"; import { FAB, IconButton, useTheme } from "react-native-paper"; export default function LoadPasswordScreen() { @@ -128,7 +128,14 @@ export default function LoadPasswordScreen() { }} showsVerticalScrollIndicator={false} ListEmptyComponent={ - + {searchQuery.trim() ? "No passwords found!!" : "No data!!"} } @@ -143,44 +150,12 @@ export default function LoadPasswordScreen() { } onLongPress={() => deletePassword(item)} > - - - Domain:{" "} - - {item.domain} - - - - - Username:{" "} - - {item.username} - - - - - Password:{" "} - - ********** - - - - - Updated At:{" "} - - {item.updatedAt == null - ? "just now" - : formatDate(item.updatedAt)} - - - + /> )} /> @@ -206,21 +181,3 @@ export default function LoadPasswordScreen() { ); } - -const styles = StyleSheet.create({ - label: { - fontWeight: "600", - marginBottom: 6, - }, - - value: { - fontWeight: "400", - }, - - emptyText: { - textAlign: "center", - marginTop: 40, - fontSize: 12, - color: "gray", - }, -}); diff --git a/src/components/PasswordItemCard.tsx b/src/components/PasswordItemCard.tsx new file mode 100644 index 00000000..745dfa0e --- /dev/null +++ b/src/components/PasswordItemCard.tsx @@ -0,0 +1,72 @@ +import Text from "@/components/Text"; +import formatDate from "@/utils/formating"; +import { StyleSheet, View, ViewStyle } from "react-native"; +import { useTheme } from "react-native-paper"; + +type Props = { + domain: string; + username: string; + updatedAt: string | null; + style?: ViewStyle; +}; + +export default function PasswordItemCard({ + domain, + username, + updatedAt, + ...props +}: Props) { + const theme = useTheme(); + + return ( + + + Domain:{" "} + + {domain} + + + + + Username:{" "} + + {username} + + + + + Password:{" "} + + ********** + + + + + Updated At:{" "} + + {updatedAt ? formatDate(updatedAt) : "just now"} + + + + ); +} + +const styles = StyleSheet.create({ + label: { + fontWeight: "600", + marginBottom: 6, + }, + + value: { + fontWeight: "400", + }, +}); From dcbcd26e973db2d1ee29a1b4f4eed1dc0d88a7e4 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Tue, 18 Aug 2026 13:01:39 +0530 Subject: [PATCH 02/12] chore: deleted unwanted files Signed-off-by: Jeel Dobariya --- assets/images/android-icon-background.png | Bin 5549 -> 0 bytes assets/images/android-icon-foreground.png | Bin 12867 -> 0 bytes assets/images/android-icon-monochrome.png | Bin 1426 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/images/android-icon-background.png delete mode 100644 assets/images/android-icon-foreground.png delete mode 100644 assets/images/android-icon-monochrome.png diff --git a/assets/images/android-icon-background.png b/assets/images/android-icon-background.png deleted file mode 100644 index ddcc8353cafc8d6ab7d695c8570e4ad2658d8328..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5549 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 diff --git a/assets/images/android-icon-foreground.png b/assets/images/android-icon-foreground.png deleted file mode 100644 index 9f802d1aa513bb8bdc4db1fee51b2301dda4507a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12867 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 fQsdZ9Mf(nGxd zjr?h6GWKE}g*{dx(p3%yw`6>|ao^i#MXU-`gRvyQ6h+8=k^OC7!jMnL@BG*=h2oQv zes1)>tGe)oeftbj1u9~61}vbgmOytE^sCH9#JDJh#5rfqS}S&(Uh9thagAU5_lSjb zg3s@?JzD5VEJL{o1&EKmU&B)oYbP@#WM*~lbCM7RQfTP;+`p2*{k=8PlZx!|0zKj$ zwkeY%J*{Rn$GlStpx539+g$;sy7h4?uG#UEP{WhtP>c6}nuI=T0;}K=;~+kE44D4K zFzST8VHl#G`Oj1sE5ElkI1t~*G8Y*Sk)Kecnd?G8o@|;M-*SLZdwHZw)>~+WlhrZ+_=z&w@-n@{2 z)uX3MJDOeKr(+ zv$p@GfV^v))(=IQpr_>mVvd*2=I;M_35qc8^mX{QJ}MREj;}Ke%y;!{4EA=WX`N-b z?2;eWX~z4Cl^xbCaZ~;*mNnn>-k~VBuF&{?g|}j!@!)BYP)KnasPNT*D38 z@@f~QyWWhSOQQY>3_m=7h8b}{7*Rz+4}y=wS?j*!u>P88gfJSm?dyRPSqkd-VLMERo&3E3e_5uE*VT8e$a**Nn$96d;p0b+>?X6y`K=Be z+sCpMj9DwO;n@l@0}Q7=}~L$Z#isL4vZD!Ed^Eb_BTKa z+q}s>`%1b)HeK!E?iiBZBfL5)Wg4A|HD;PkUfW(Hk38@_yne#l=}Xk_(%kHVze1UQ zWLho5LKh?naSHH{e7Ry#T5?tWkgWtR&=jz#C6Ja6x05& z>L1Hg7XX(65`W#}+w1O1&^CT=S02U1pD}u11?PyTAK-d43UEaPs1aYIgLx?tJ%6%3 zeE#(G8siLK%A@(Zje2~sChbn>pYgD-SrPz8CQEYi6B6Zh&C->2<0WoJyI+65upW1wKTV|x3CQ3vQb0aj97B}D?&g>u*^zUq z^09xFYXwLSe)f3RzAgoeNB8HS-uH zA$^x%V8%`qy8D5}|4t@d*CZ&EJhcILUpkA@`qD1!YUXY4`&A3*Mc{L)bL^LoN1lp| zXPy=ig+=IXV*Ai(45^7_MnuQWjiYImpg zFPdObq#8<2>v z!&_z+m(vx(6m@#<1v-H+Oi~WYspgb?+LXYbB7-}oXaX**b;5TvAT7@J<_`lI%HfHE zw~tQeT-TBPwHd#iDfxgY*Q1uR_Fq!X^F!q$HYh(#6>@xOqtJ0KdhsFSbT&EeD(gHj zoAGb@@~lJ!&!Cc+?kNjR_g8~|DSe;SoOGrI+_F6TD!pJ1A6EA4T|?M;ACn%&&YmOo z#1n`9lXw+fH80KiZR}X0SZUo;WJ33fyH@(f<8q9!{<8b(JpEo*b)H3c_#YjobIl7Q zt8)F0l&Z#swzf;RBB?8Py!L(Otnvr#;)#P5<|N32>-JNPS(^CFFT!SPD diff --git a/assets/images/android-icon-monochrome.png b/assets/images/android-icon-monochrome.png deleted file mode 100644 index b484d83cf472a3cb81440a67d4d92c940fdb3f7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1426 zcmZuxc{mdc7@u=;Y$QifvptSYmhdr|GRGW=9E&Z!HJR_@$x)72a_5R>k`ZQ=T!l2( zkSJjyXSqfwceC`A`RFWRTZ@+zfsLrnIfN;IG@KsUjjQ+>hm01f^MrR@pzk`_GmRCLr z!V*)OVzpS3bWX64J^6rXX248pMS=#aH)N7}!k~!4R4>)bW7-9q6j5%TkI#A~KTgec zhxqOfNf&Yy*Q~As&y&S;GBpGUYSfxFh68Q%+&o0)+`4 z<{>yPT*x6dtbzl`^9qmq5ei=9)GX9$>#a+umI9<~;}V^JV}kWGaQQ@O_!-6VAx0nM z0-+x4Dc&_#H33{9g|W-6+4}f?_d$sq(p9;tD==v3bni-c$3+JTtNG*#9ywEu;=Gqi-!uS$mG zkTu}HhGb+DHC&H8>RZ<62lZ(83;1ABFT1B{mt*1fIoJq6j(N}M$!=GZ#sUvmN@<&O zdGNS{V?&AdxvbJSf)%sFRgwb*xtsp&tut*;+(L%Vr2AEu(v}11%XO0X1MB=hJ+LV8 z(Ba>(J#0qW0e{qwelSiiAzHsKN1l^Lz-IC3A24Yc>yfO1LKrQo;yFDHQ}R!7iH4eY zehBZ*dtzrB}k22cxH^%}raU3}N4M-@FCohB5 zg_F@oywRFu)j-oEjK#?3Z=O)F8~)pd$Z1+Msmp_8{nr#C!3ASBV9-RBS^~ORGmV9y zT*Q`tyPa`g20lz#5@vAVcwAeh41Y>V?^2nC`$+f zOd=}T;l)O>DHkt6*&Mm|E8?Ar&R_B)&F>s{7s>n7BCpfamzRn zuRU=pEJFK$;d{pg{K8yL4R3lPXk>2gW|^R&!U|9C6+2^RHQG6+dcEAK<59DE@(mR! z_3eg)f~=qwN*W^o&FfEXU-}w=+S{AxUq^*;qFeV)3;+3z{m;(SC^4krFNYjUMt|3K LSVyZW3sU@lL Date: Mon, 31 Aug 2026 21:09:04 +0530 Subject: [PATCH 03/12] refactor: passcodes detail screen Signed-off-by: Jeel Dobariya --- .../(password-manager)/password-details.tsx | 130 ++++-------------- src/components/PasswordDetailCardActions.tsx | 54 ++++++++ src/components/PasswordFormCard.tsx | 112 +++++++++++++++ 3 files changed, 189 insertions(+), 107 deletions(-) create mode 100644 src/components/PasswordDetailCardActions.tsx create mode 100644 src/components/PasswordFormCard.tsx diff --git a/src/app/(tabs)/(password-manager)/password-details.tsx b/src/app/(tabs)/(password-manager)/password-details.tsx index 193be56a..42510c31 100644 --- a/src/app/(tabs)/(password-manager)/password-details.tsx +++ b/src/app/(tabs)/(password-manager)/password-details.tsx @@ -1,5 +1,7 @@ -import FormTextField from "@/components/FormTextField"; -import SecureTextField from "@/components/SecureTextField"; +import PasswordDetailCardActions from "@/components/PasswordDetailCardActions"; +import PasswordFormCard, { + usePasswordForm, +} from "@/components/PasswordFormCard"; import { useToast } from "@/contexts/ToastContext"; import { passwords } from "@/db/schema"; @@ -14,9 +16,9 @@ import { usePreventRemove } from "expo-router/react-navigation"; import { useSQLiteContext } from "expo-sqlite"; import { useEffect, useState } from "react"; -import { Keyboard, ScrollView, TextInput, View } from "react-native"; +import { Keyboard, ScrollView, TextInput } from "react-native"; -import { Button, FAB } from "react-native-paper"; +import { FAB } from "react-native-paper"; import { SafeAreaView } from "react-native-safe-area-context"; export default function PasswordDetailsScreen() { @@ -25,13 +27,7 @@ export default function PasswordDetailsScreen() { const db = useSQLiteContext(); const drizzleDb = drizzle(db); - const [domain, setDomain] = useState(""); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [url, setUrl] = useState(""); - const [notes, setNotes] = useState(""); - const [lastupdateAt, setLastupdateAt] = useState(""); - + const { state, setState, updateField } = usePasswordForm(); const [isEditing, setIsEditing] = useState(false); const { showToast } = useToast(); @@ -60,12 +56,14 @@ export default function PasswordDetailsScreen() { if (result.length > 0) { const data = result[0]; - setDomain(data.domain || ""); - setUsername(data.username || ""); - setPassword(data.password || ""); - setUrl(data.url || ""); - setNotes(data.notes || ""); - setLastupdateAt(data.updatedAt ? formatDate(data.updatedAt) : "just now"); + setState({ + domain: data.domain || "", + username: data.username || "", + password: data.password || "", + url: data.url || "", + notes: data.notes || "", + updatedAt: data.updatedAt ? formatDate(data.updatedAt) : "just now", + }); } } @@ -81,14 +79,7 @@ export default function PasswordDetailsScreen() { try { await drizzleDb .update(passwords) - .set({ - domain, - username, - password, - url, - notes, - updatedAt: new Date().toISOString(), - }) + .set({ ...state, updatedAt: new Date().toISOString() }) .where(eq(passwords.id, Number(id))); setIsEditing(false); @@ -142,92 +133,17 @@ export default function PasswordDetailsScreen() { }} keyboardShouldPersistTaps="handled" > - - - - - - - - router.navigate(state.url as Href)} + onCancel={handleCancel} /> - - - - - {!isEditing && ( - - )} - - {isEditing && ( - - )} - void; + onCancel: () => void; +}) { + return ( + + {!isEditing && ( + + )} + + {isEditing && ( + + )} + + ); +} diff --git a/src/components/PasswordFormCard.tsx b/src/components/PasswordFormCard.tsx new file mode 100644 index 00000000..c750c8c4 --- /dev/null +++ b/src/components/PasswordFormCard.tsx @@ -0,0 +1,112 @@ +import FormTextField from "@/components/FormTextField"; +import SecureTextField from "@/components/SecureTextField"; +import { useState } from "react"; + +import { View } from "react-native"; + +type PasswordFormValue = { + domain: string; + username: string; + password: string; + url: string; + notes: string; + updatedAt: string; +}; + +// xxxxx Component xxxxx + +type PasswordFormCardProps = { + value: PasswordFormValue; + editable: boolean; + + onChange: ( + field: K, + value: PasswordFormValue[K], + ) => void; +}; + +export default function PasswordFormCard({ + value, + editable, + onChange, +}: PasswordFormCardProps) { + return ( + + onChange("domain", text)} + editable={editable} + /> + + onChange("username", text)} + editable={editable} + autoCapitalize="none" + autoCorrect={false} + /> + + onChange("password", text)} + editable={editable} + /> + + onChange("url", text)} + editable={editable} + autoCapitalize="none" + autoCorrect={false} + /> + + onChange("notes", text)} + editable={editable} + multiline + numberOfLines={3} + /> + + + + ); +} + +// xxxxx Hook xxxxx + +export function usePasswordForm() { + const [state, setState] = useState({ + domain: "", + username: "", + password: "", + url: "", + notes: "", + updatedAt: "", + }); + + function updateField( + field: K, + value: PasswordFormValue[K], + ) { + setState((current) => ({ + ...current, + [field]: value, + })); + } + + return { + state, + setState, + updateField, + }; +} From abe8ba442d48e9f073984c07e04c9bbabd6e4349 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 4 Sep 2026 11:19:45 +0530 Subject: [PATCH 04/12] refactor: passcodesalgo Signed-off-by: Jeel Dobariya --- package-lock.json | 6 ++++++ package.json | 1 + .../(password-manager)/password-details.tsx | 2 +- src/components/PasswordItemCard.tsx | 2 +- src/utils/formating.ts | 20 ------------------- 5 files changed, 9 insertions(+), 22 deletions(-) delete mode 100644 src/utils/formating.ts diff --git a/package-lock.json b/package-lock.json index de3cfaee..331e752b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "passcodes", "version": "1.0.0", "dependencies": { + "@passcodes/passalgo": "github:PasscodesApp/PassAlgo#main", "@react-native-community/slider": "5.2.0", "@react-native-vector-icons/fontawesome6": "^13.1.2", "@shopify/flash-list": "2.0.2", @@ -3345,6 +3346,11 @@ "node": ">=12.4.0" } }, + "node_modules/@passcodes/passalgo": { + "version": "0.1.0", + "resolved": "git+ssh://git@github.com/PasscodesApp/PassAlgo.git#17e4baf73539584f4144e2feb83aa651bfb0504d", + "license": "MIT" + }, "node_modules/@radix-ui/primitive": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", diff --git a/package.json b/package.json index 44ba8743..67800c2c 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "deploy:x86_64": "eas build --profile deploy-x86_64 --platform android --local" }, "dependencies": { + "@passcodes/passalgo": "github:PasscodesApp/PassAlgo#main", "@react-native-community/slider": "5.2.0", "@react-native-vector-icons/fontawesome6": "^13.1.2", "@shopify/flash-list": "2.0.2", diff --git a/src/app/(tabs)/(password-manager)/password-details.tsx b/src/app/(tabs)/(password-manager)/password-details.tsx index 42510c31..c7034380 100644 --- a/src/app/(tabs)/(password-manager)/password-details.tsx +++ b/src/app/(tabs)/(password-manager)/password-details.tsx @@ -6,7 +6,7 @@ import { useToast } from "@/contexts/ToastContext"; import { passwords } from "@/db/schema"; import { getScreenShotSecureScreen } from "@/libs/screenshot_prevention"; -import formatDate from "@/utils/formating"; +import { formatDate } from "@passcodes/passalgo"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; import { eq } from "drizzle-orm"; diff --git a/src/components/PasswordItemCard.tsx b/src/components/PasswordItemCard.tsx index 745dfa0e..7d062d62 100644 --- a/src/components/PasswordItemCard.tsx +++ b/src/components/PasswordItemCard.tsx @@ -1,5 +1,5 @@ import Text from "@/components/Text"; -import formatDate from "@/utils/formating"; +import { formatDate } from "@passcodes/passalgo"; import { StyleSheet, View, ViewStyle } from "react-native"; import { useTheme } from "react-native-paper"; diff --git a/src/utils/formating.ts b/src/utils/formating.ts deleted file mode 100644 index 33617e62..00000000 --- a/src/utils/formating.ts +++ /dev/null @@ -1,20 +0,0 @@ -export default function formatDate(isoString: string): string { - const date = new Date(isoString); - - const months = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "June", - "July", - "Augt", - "Sept", - "Oct", - "Nov", - "Dec", - ]; - - return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`; -} From a82716c0d1247b22fcfd56ea0fe410a75f68fc8d Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 4 Sep 2026 11:36:42 +0530 Subject: [PATCH 05/12] chore(deps): latest dependency Signed-off-by: Jeel Dobariya --- package-lock.json | 188 +++++++++++++++++++++++----------------------- package.json | 12 +-- 2 files changed, 100 insertions(+), 100 deletions(-) diff --git a/package-lock.json b/package-lock.json index 331e752b..c06c6a0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,20 +14,20 @@ "@shopify/flash-list": "2.0.2", "babel-plugin-inline-import": "^3.0.0", "drizzle-orm": "^0.45.2", - "expo": "~57.0.18", - "expo-build-properties": "~57.0.15", + "expo": "~57.0.19", + "expo-build-properties": "~57.0.16", "expo-clipboard": "~57.0.1", "expo-constants": "~57.0.3", - "expo-dev-client": "~57.0.16", + "expo-dev-client": "~57.0.18", "expo-file-system": "~57.0.0", "expo-linear-gradient": "~57.0.1", - "expo-linking": "~57.0.8", + "expo-linking": "~57.0.9", "expo-local-authentication": "~57.0.2", "expo-navigation-bar": "~57.0.2", - "expo-router": "~57.0.17", + "expo-router": "~57.0.18", "expo-screen-capture": "~57.0.2", "expo-screen-orientation": "~57.0.2", - "expo-sharing": "~57.0.16", + "expo-sharing": "~57.0.17", "expo-splash-screen": "~57.0.8", "expo-sqlite": "~57.0.2", "expo-status-bar": "~57.0.1", @@ -2389,9 +2389,9 @@ "license": "MIT" }, "node_modules/@expo/fingerprint": { - "version": "0.20.11", - "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.20.11.tgz", - "integrity": "sha512-GC43EcjQwzpzNZISqmhvjKdi+6FTfxnC9ZxOeg6osCkYXJz94j107l0QpPLipg62khD5HAA5G5cUhevffbRC4w==", + "version": "0.20.12", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.20.12.tgz", + "integrity": "sha512-FIR5fkZYeFaLSowmjgyB6RPKl8AXeE8HuCBHHvyxK8UhOjpPfCAmzT4E7v2yub4qqDafKnfcOFCYxvpUEu+01w==", "license": "MIT", "dependencies": { "@expo/env": "^2.4.3", @@ -2607,9 +2607,9 @@ } }, "node_modules/@expo/metro-runtime": { - "version": "57.0.14", - "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-57.0.14.tgz", - "integrity": "sha512-LVpsfF0QOzlLSKlHYpxgW1cP1NKcYeaoalLO18jYHgqseSveEkb9VOffFpicTQ7AN03odZ4fgkUF+p5YpoY4yw==", + "version": "57.0.15", + "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-57.0.15.tgz", + "integrity": "sha512-9RaFkqIzRud6ol9fc5ZKHgNDYeDjQVBdAQC+rjSQ6RiKV0pY+SjDqGmKY5a4M9TaV0qLMCNNrp5R88BqC2xbuQ==", "license": "MIT", "dependencies": { "@expo/log-box": "^57.0.4", @@ -3113,9 +3113,9 @@ "license": "MIT" }, "node_modules/@expo/ui": { - "version": "57.0.14", - "resolved": "https://registry.npmjs.org/@expo/ui/-/ui-57.0.14.tgz", - "integrity": "sha512-m8Z5dCplkOOQ70lu/xfB67qhk00Muw4U1T9frHBIW3LxxJeJZQ+jOmV6vCk6O6zVgoG/ib1et7PeX6etxI4Rsw==", + "version": "57.0.15", + "resolved": "https://registry.npmjs.org/@expo/ui/-/ui-57.0.15.tgz", + "integrity": "sha512-qNntEAbDEq0VGkAUMaopIZLJEZofQMDJNjx8YBngqeG3oZJKjpQFOSI8ui951NbN8nABzJ5Jd55SXdZKYWslDw==", "license": "MIT", "dependencies": { "sf-symbols-typescript": "^2.1.0", @@ -5072,9 +5072,9 @@ } }, "node_modules/agent-cli-detector": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/agent-cli-detector/-/agent-cli-detector-0.1.6.tgz", - "integrity": "sha512-vKrPeEVN3upDF3GjWxsWBbwQgMtNJ8VB1cduPvK3svmmz4ENpS7yaPxbogsbe3w+xp9xp2Cu+0Ar41rjAR4+lA==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/agent-cli-detector/-/agent-cli-detector-0.1.7.tgz", + "integrity": "sha512-d8OWDVdZMgjhLUT9ZPgSv/BdFFF9pVuscC0JdUSz3bjwE15gcp6u/o0/JooM2yyAWC49KThFhXlgTXRa9B7yng==", "license": "MIT", "bin": { "agent-cli-detector": "dist/cli.js" @@ -5483,9 +5483,9 @@ } }, "node_modules/babel-preset-expo": { - "version": "57.0.9", - "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-57.0.9.tgz", - "integrity": "sha512-T19biGOBTnMp161PyBqWOoSIEeZug8/EjtuUdVob8JPQKZMTalHUQaQt+qtQQE7XsEkZJ6erb3k0CohneTFzQg==", + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-57.0.10.tgz", + "integrity": "sha512-08bt6bqMZFoQuWO9gkt0EXotbqKHimELFGa1LlKJvY89iKsi4S0FJSFBFJ4pn9NZvofet48HIjYDQ0SZJ7bNrg==", "license": "MIT", "dependencies": { "@babel/generator": "^7.20.5", @@ -5534,7 +5534,7 @@ "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", - "expo-widgets": "^57.0.13", + "expo-widgets": "^57.0.16", "react-refresh": ">=0.14.0 <1.0.0" }, "peerDependenciesMeta": { @@ -7327,31 +7327,31 @@ } }, "node_modules/expo": { - "version": "57.0.18", - "resolved": "https://registry.npmjs.org/expo/-/expo-57.0.18.tgz", - "integrity": "sha512-6nax9hJPhf9dWrstliXUABTJXDNIJrfJKcCtjSxuYVs2Yf127GIhKf3wsEYSFUl+LFdRbPPTNaweJePH159wZA==", + "version": "57.0.19", + "resolved": "https://registry.npmjs.org/expo/-/expo-57.0.19.tgz", + "integrity": "sha512-oIoAIisim1DwS2Zjp0rcEY9cfcq1wU6KpkBfwwFhJWI5YHV6i/aIzTUMX+uf0Q0CD6AvMls7IZVh34o27NjaJA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "^57.0.20", + "@expo/cli": "^57.0.21", "@expo/config": "~57.0.9", "@expo/config-plugins": "~57.0.9", "@expo/devtools": "~57.0.1", "@expo/dom-webview": "~57.0.1", - "@expo/fingerprint": "^0.20.11", + "@expo/fingerprint": "^0.20.12", "@expo/local-build-cache-provider": "^57.0.8", "@expo/log-box": "^57.0.4", "@expo/metro": "~56.0.2", "@expo/metro-config": "~57.0.12", "@ungap/structured-clone": "^1.3.0", - "babel-preset-expo": "~57.0.9", - "expo-asset": "~57.0.15", - "expo-constants": "~57.0.16", + "babel-preset-expo": "~57.0.10", + "expo-asset": "~57.0.16", + "expo-constants": "~57.0.17", "expo-file-system": "~57.0.6", - "expo-font": "~57.0.2", + "expo-font": "~57.0.3", "expo-keep-awake": "~57.0.1", "expo-modules-autolinking": "~57.0.12", - "expo-modules-core": "~57.0.14", + "expo-modules-core": "~57.0.15", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.2" @@ -7389,13 +7389,13 @@ } }, "node_modules/expo-asset": { - "version": "57.0.15", - "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-57.0.15.tgz", - "integrity": "sha512-ZoiUftQb1Nn1jvL6l1kZoUXvgRCx57tMQYxSsp+g4ZvY+jgVWp/THruXOtPtZVdC/WWZxPUTct53bfAm2EPDAQ==", + "version": "57.0.16", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-57.0.16.tgz", + "integrity": "sha512-IBRfQdW3iFT+GOBERMZLZM1MUNyrjMgMskuD0elVZ1ae44858UFlTJkHO3f8vi+u5zuv7O7KofsiN8NMG/uWzw==", "license": "MIT", "dependencies": { "@expo/image-utils": "^0.11.5", - "expo-constants": "~57.0.15" + "expo-constants": "~57.0.17" }, "peerDependencies": { "expo": "*", @@ -7431,9 +7431,9 @@ } }, "node_modules/expo-build-properties": { - "version": "57.0.15", - "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-57.0.15.tgz", - "integrity": "sha512-qZe9pnxlBpHT7SSNDR2a3C+P34xv67Ep9I0Erh+3xCczGlokyRd4pu9h0PrBdsVlr1d0QREQ1Do/+IgrIWkQQA==", + "version": "57.0.16", + "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-57.0.16.tgz", + "integrity": "sha512-snEQKIn/sMEAFUc8x2aQTQa/rzJbfjsuLJ9YcGUh5iCN65nid7R2V8J3PKyMUFPVEST+cDNf8WDlgN8jOuveXw==", "license": "MIT", "dependencies": { "@expo/schema-utils": "^57.0.2", @@ -7468,9 +7468,9 @@ } }, "node_modules/expo-constants": { - "version": "57.0.16", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.16.tgz", - "integrity": "sha512-HG3yJjGZo2BPTo2F1sBoxdJZRwX7d9C554EhKn8m12K62pxGolCsvPSoh/lQf95OEP9vO34wwXB2C3QFs0KG0g==", + "version": "57.0.17", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.17.tgz", + "integrity": "sha512-cPWYBKN1SEbg2lXg2f8VkePJqGZrJPLvVdQDCTfbFu9sQHO1M31Y1zILReUuGnmt/VKeUz40ze579vR00xGu/A==", "license": "MIT", "dependencies": { "@expo/env": "~2.4.3" @@ -7481,13 +7481,13 @@ } }, "node_modules/expo-dev-client": { - "version": "57.0.16", - "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-57.0.16.tgz", - "integrity": "sha512-Txss9sgzEFI0E+4I34E76vPiukeVDHnqCj0ZXy8SDijVM31/P6MCNniVbEZk7MBPQclD0aopfuaCFtkV8+r1sw==", + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-57.0.18.tgz", + "integrity": "sha512-cT+6iO4rRoguIxeONAPHF2wbAlc002tZya2M3xHlc6EWKptjsAL2Vr+kagYdLH/4vtLX7XKhWvOzaBf+rQpRFg==", "license": "MIT", "dependencies": { - "expo-dev-launcher": "~57.0.16", - "expo-dev-menu": "~57.0.16", + "expo-dev-launcher": "~57.0.19", + "expo-dev-menu": "~57.0.18", "expo-dev-menu-interface": "~57.0.0", "expo-manifests": "~57.0.1", "expo-updates-interface": "~57.0.1" @@ -7497,13 +7497,13 @@ } }, "node_modules/expo-dev-launcher": { - "version": "57.0.16", - "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-57.0.16.tgz", - "integrity": "sha512-jaBr6q4A5js/r465m2mRxN8A87YOi8I6PiIt8XIt4qfQWDgw6hqGovaF1AVFGT1Z5jxkjtgK8WNz/rAeypjqPQ==", + "version": "57.0.19", + "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-57.0.19.tgz", + "integrity": "sha512-IF/EJ3tcHqiyfBb5VtpAU3upBXRVTFVuVoWqEzrkZCesuMi35td4yQFvPtqXbMceaEErgFyiyxhW+L6AXVYapA==", "license": "MIT", "dependencies": { "@expo/schema-utils": "^57.0.2", - "expo-dev-menu": "~57.0.16", + "expo-dev-menu": "~57.0.18", "expo-manifests": "~57.0.1" }, "peerDependencies": { @@ -7512,9 +7512,9 @@ } }, "node_modules/expo-dev-menu": { - "version": "57.0.16", - "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-57.0.16.tgz", - "integrity": "sha512-KzMHtAmnr0GqyU6MCrKLzIo/AfOjcToGhzK+pFeXlcqSPOrPJbTGlZqQ3E1o2G2jZMs+M1XvXh/VgnRyJUaRGw==", + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-57.0.18.tgz", + "integrity": "sha512-H7m9ENtVYz4FpJktQj+z/njIN1t7kOEaKCv8Qgv2SdAlyFTW8s2EnufxPoSlg2zUTanaauJ6wrR6XESHwW7kpw==", "license": "MIT", "dependencies": { "expo-dev-menu-interface": "~57.0.0" @@ -7557,9 +7557,9 @@ } }, "node_modules/expo-font": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.2.tgz", - "integrity": "sha512-eWR0CAdysgVqg8VewJ8b5wKh1pa6C8YShIEU3SP0+hlSqOk4djUwuJjn3P04KHVzL3hws9FrUuPxCNmd4TGung==", + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.3.tgz", + "integrity": "sha512-kiVUnc2A8vAvO2FfDJTsQa5BwmY+PAkof/1wRb5MOkcX1jtiaSTwz9gCUAyscMBFLundZDmZrLy1P7LZVC+NvA==", "license": "MIT", "dependencies": { "fontfaceobserver": "^2.1.0" @@ -7609,12 +7609,12 @@ } }, "node_modules/expo-linking": { - "version": "57.0.8", - "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-57.0.8.tgz", - "integrity": "sha512-gv0ZNaF7tILbcvX8xinNbQr6GIGQStxeUAJseweP+LjC9ped7Wl6EeyIMBlDR83U6Da+8drVeqBQSMvwAXgytA==", + "version": "57.0.9", + "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-57.0.9.tgz", + "integrity": "sha512-TQJe3NsnpZXApBg1n6DKaZ4TNhYm+iYWq7W9rTp+G44IBMZSUcI8ba+ffYC/LMY1qw+95AuBPIF1zTx1NQoTXw==", "license": "MIT", "dependencies": { - "expo-constants": "~57.0.15", + "expo-constants": "~57.0.17", "invariant": "^2.2.4" }, "peerDependencies": { @@ -7662,13 +7662,13 @@ } }, "node_modules/expo-modules-core": { - "version": "57.0.14", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-57.0.14.tgz", - "integrity": "sha512-Cg3aQnVsQhZcMOF/RFgPGzMuhIak5W9eR9ecwmFSeQ813r4/49ut6RMA6PqUuUKuPCUIRqnBAHfSyTm1W9nfzg==", + "version": "57.0.15", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-57.0.15.tgz", + "integrity": "sha512-HBxPXsx3eVLLRjAY57/8ghKDWIxjaEbluKKYFIq1OHPJC85ZfHsawwc0SOU4Z/qu+mdLz7Pwt5IkkWimeNSH5A==", "license": "MIT", "dependencies": { "@expo/expo-modules-macros-plugin": "0.6.1", - "expo-modules-jsi": "~57.0.6", + "expo-modules-jsi": "~57.0.7", "invariant": "^2.2.4" }, "peerDependencies": { @@ -7683,9 +7683,9 @@ } }, "node_modules/expo-modules-jsi": { - "version": "57.0.6", - "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-57.0.6.tgz", - "integrity": "sha512-WK0xFEe0FdZTCLCdfXK+HVNYfAmEbA6goecRxqjr0gh3XYRKAr9tikxqcM0ItLQoEPKntscPZhWcPLGvr97Tfw==", + "version": "57.0.7", + "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-57.0.7.tgz", + "integrity": "sha512-/GOrTFPnCfg7+m6M1yOSEKNeNdHBCm0ju6aJ4XHlSmtE02nb7mWh1Cs6QsK2eB5Rz7hjbb356Nd7UimsFvN7Vg==", "license": "MIT", "peerDependencies": { "react-native": "*" @@ -7706,15 +7706,15 @@ } }, "node_modules/expo-router": { - "version": "57.0.17", - "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-57.0.17.tgz", - "integrity": "sha512-zKAfGLxrbdkUFzzW1xHezLXPSa0V4DlYKEWweDUUFGgnPWPNy3OY0EKYAqOhlBGSDebAvtnJXn+2zyyJjYKwyg==", + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-57.0.18.tgz", + "integrity": "sha512-Mj4uv88J6QQLC46GQlCNIwH6kd1685x52RdcQuGIGt5nZk4axfRJOjd0zqXZQzSqOR8bbkuufHMM+dYKtCdVvA==", "license": "MIT", "dependencies": { "@expo/log-box": "^57.0.4", - "@expo/metro-runtime": "^57.0.14", + "@expo/metro-runtime": "^57.0.15", "@expo/schema-utils": "^57.0.2", - "@expo/ui": "^57.0.14", + "@expo/ui": "^57.0.15", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-native-masked-view/masked-view": "^0.3.2", @@ -7741,11 +7741,11 @@ }, "peerDependencies": { "@expo/log-box": "^57.0.4", - "@expo/metro-runtime": "^57.0.14", + "@expo/metro-runtime": "^57.0.15", "@testing-library/react-native": ">= 13.2.0", "expo": "*", - "expo-constants": "^57.0.15", - "expo-linking": "^57.0.8", + "expo-constants": "^57.0.17", + "expo-linking": "^57.0.9", "react": "*", "react-dom": "*", "react-native": "*", @@ -7807,9 +7807,9 @@ } }, "node_modules/expo-sharing": { - "version": "57.0.16", - "resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-57.0.16.tgz", - "integrity": "sha512-Z4ZFYLP8+EqIdUAiERYRI4/r7rtZDCRQ8Lj6jDG0xPF19B8nsFhYMgh7uyic+WulFEr+Xn7FeWgSDAuufkOyzw==", + "version": "57.0.17", + "resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-57.0.17.tgz", + "integrity": "sha512-p2B4SMeNsOv6hm1NkrxRlncjwu9mmLfi0drLaEyX13Rxn4DdDFPhuaezpOK7XLogTsmWGpfR46uq6oHMvSxbfA==", "license": "MIT", "dependencies": { "@expo/config-plugins": "^57.0.9", @@ -7907,9 +7907,9 @@ } }, "node_modules/expo/node_modules/@expo/cli": { - "version": "57.0.20", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-57.0.20.tgz", - "integrity": "sha512-ZjWz7SA5TBTyKq4+aFRUPgMFxmqHtKkDMv6d85J2UAAjdRhkNRf+B80t+rr5IFo2ywuTvyrPRBth4ei4w08olA==", + "version": "57.0.21", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-57.0.21.tgz", + "integrity": "sha512-CkcgAOsp1KkNRENXWfyr/esIwgFtiHosKECWZ0QQl2nFOUEQlyjWXAZ6uTCMnbHLonVnPMZpXTkHZNw3gtanFw==", "license": "MIT", "dependencies": { "@expo/code-signing-certificates": "^0.0.6", @@ -7929,14 +7929,14 @@ "@expo/plist": "^0.8.1", "@expo/prebuild-config": "^57.0.15", "@expo/require-utils": "^57.0.5", - "@expo/router-server": "^57.0.8", + "@expo/router-server": "^57.0.9", "@expo/schema-utils": "^57.0.2", "@expo/spawn-async": "^1.8.0", "@expo/ws-tunnel": "^2.0.0", "@expo/xcpretty": "^4.4.4", "@react-native/dev-middleware": "0.86.3", "accepts": "^1.3.8", - "agent-cli-detector": "0.1.6", + "agent-cli-detector": "0.1.7", "arg": "^5.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", @@ -7990,18 +7990,18 @@ } }, "node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { - "version": "57.0.8", - "resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-57.0.8.tgz", - "integrity": "sha512-lEPGYoDmh97yyEcY/MFWQsfE7yIgMRnGDcnsBN7B6AiWBFSJIMEcGnO0aYPgY0ZjNWyJDi7Ee8QZRGqB+LhI6w==", + "version": "57.0.9", + "resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-57.0.9.tgz", + "integrity": "sha512-/PxRQozFesIyCJZOAtrQE8XcmcojNiL5ctPMQnbE4ojC2EJPu0zc7c0Y4PuXsoRxrZxm8Usw76/lCVrXcfTZ2w==", "license": "MIT", "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { - "@expo/metro-runtime": "^57.0.14", + "@expo/metro-runtime": "^57.0.15", "expo": "*", - "expo-constants": "^57.0.15", - "expo-font": "^57.0.1", + "expo-constants": "^57.0.17", + "expo-font": "^57.0.3", "expo-router": "*", "expo-server": "^57.0.3", "react": "*", @@ -11489,9 +11489,9 @@ } }, "node_modules/postcss": { - "version": "8.5.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", - "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", "funding": [ { "type": "opencollective", @@ -11508,7 +11508,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.17", + "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, diff --git a/package.json b/package.json index 67800c2c..e485343b 100644 --- a/package.json +++ b/package.json @@ -24,20 +24,20 @@ "@shopify/flash-list": "2.0.2", "babel-plugin-inline-import": "^3.0.0", "drizzle-orm": "^0.45.2", - "expo": "~57.0.18", - "expo-build-properties": "~57.0.15", + "expo": "~57.0.19", + "expo-build-properties": "~57.0.16", "expo-clipboard": "~57.0.1", "expo-constants": "~57.0.3", - "expo-dev-client": "~57.0.16", + "expo-dev-client": "~57.0.18", "expo-file-system": "~57.0.0", "expo-linear-gradient": "~57.0.1", - "expo-linking": "~57.0.8", + "expo-linking": "~57.0.9", "expo-local-authentication": "~57.0.2", "expo-navigation-bar": "~57.0.2", - "expo-router": "~57.0.17", + "expo-router": "~57.0.18", "expo-screen-capture": "~57.0.2", "expo-screen-orientation": "~57.0.2", - "expo-sharing": "~57.0.16", + "expo-sharing": "~57.0.17", "expo-splash-screen": "~57.0.8", "expo-sqlite": "~57.0.2", "expo-status-bar": "~57.0.1", From e0e5f3c0703a79fb03e107cb8d7e67f21937a749 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 4 Sep 2026 13:28:34 +0530 Subject: [PATCH 06/12] refactor: custom plugins Signed-off-by: Jeel Dobariya --- app.config.ts | 4 +++- .../index.ts} | 12 +++++++++--- plugins/withProtectUserData/plugin.ts | 10 ++++++++++ tsconfig.json | 3 ++- 4 files changed, 24 insertions(+), 5 deletions(-) rename plugins/{withProtectUserData.ts => withProtectUserData/index.ts} (52%) create mode 100644 plugins/withProtectUserData/plugin.ts diff --git a/app.config.ts b/app.config.ts index de6c12ee..80f52d5a 100644 --- a/app.config.ts +++ b/app.config.ts @@ -12,6 +12,7 @@ import sharingPlugin from "expo-sharing/plugin"; import splashScreenPlugin from "expo-splash-screen/plugin"; import sqlitePlugin from "expo-sqlite/plugin"; import statusBarPlugin from "expo-status-bar/plugin"; +import withProtectUserDataPlugin from "./plugins/withProtectUserData/plugin"; const IS_DEV_BUILD = process.env.APP_VARIANT === "development"; const IS_PREVIEW_BUILD = process.env.APP_VARIANT === "preview"; @@ -145,8 +146,9 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ expoScreenOrientationPlugin({ initialOrientation: "PORTRAIT", }), + withProtectUserDataPlugin({ allowBackup: false }), // TODO: we make it to allow backup when we have encryption. + "@react-native-vector-icons/fontawesome6", - "./plugins/withProtectUserData.ts", ], experiments: { typedRoutes: true, diff --git a/plugins/withProtectUserData.ts b/plugins/withProtectUserData/index.ts similarity index 52% rename from plugins/withProtectUserData.ts rename to plugins/withProtectUserData/index.ts index 62aa1536..4055823c 100644 --- a/plugins/withProtectUserData.ts +++ b/plugins/withProtectUserData/index.ts @@ -1,16 +1,22 @@ import { ConfigPlugin, withAndroidManifest } from "expo/config-plugins"; +import { ProtectUserDataProps } from "./plugin"; -const withProtectUserData: ConfigPlugin = (config) => { +const withProtectUserDataPlugin: ConfigPlugin = ( + config, + props, +) => { return withAndroidManifest(config, (config) => { const mainApplication = config?.modResults?.manifest?.application?.[0]; if (mainApplication) { mainApplication.$["android:hasFragileUserData"] = "true"; - mainApplication.$["android:allowBackup"] = "false"; + mainApplication.$["android:allowBackup"] = props.allowBackup + ? "true" + : "false"; } return config; }); }; -export default withProtectUserData; +export default withProtectUserDataPlugin; diff --git a/plugins/withProtectUserData/plugin.ts b/plugins/withProtectUserData/plugin.ts new file mode 100644 index 00000000..617efdb7 --- /dev/null +++ b/plugins/withProtectUserData/plugin.ts @@ -0,0 +1,10 @@ +export type ProtectUserDataProps = { + /** Whether to allow Android to back up the app's data. */ + allowBackup: boolean; +}; + +export default function withProtectUserDataPlugin( + props: ProtectUserDataProps = { allowBackup: false }, +): [string, ProtectUserDataProps] { + return ["@plugins/withProtectUserData", props]; +} diff --git a/tsconfig.json b/tsconfig.json index ec96c84d..b9cdd7ea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "strict": true, "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@plugins/*": ["./plugins/*"] } }, "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"] From 089eab4039abbd4c6e023fe943401b7b9c7d085c Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Sat, 12 Sep 2026 21:19:27 +0530 Subject: [PATCH 07/12] chore: update depedency Signed-off-by: Jeel Dobariya --- package-lock.json | 518 +++++++++++++++++++++++----------------------- package.json | 26 +-- 2 files changed, 272 insertions(+), 272 deletions(-) diff --git a/package-lock.json b/package-lock.json index c06c6a0a..cb95000b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,24 +14,24 @@ "@shopify/flash-list": "2.0.2", "babel-plugin-inline-import": "^3.0.0", "drizzle-orm": "^0.45.2", - "expo": "~57.0.19", - "expo-build-properties": "~57.0.16", - "expo-clipboard": "~57.0.1", + "expo": "~57.0.22", + "expo-build-properties": "~57.0.17", + "expo-clipboard": "~57.0.2", "expo-constants": "~57.0.3", - "expo-dev-client": "~57.0.18", + "expo-dev-client": "~57.0.19", "expo-file-system": "~57.0.0", - "expo-linear-gradient": "~57.0.1", - "expo-linking": "~57.0.9", - "expo-local-authentication": "~57.0.2", + "expo-linear-gradient": "~57.0.2", + "expo-linking": "~57.0.10", + "expo-local-authentication": "~57.0.3", "expo-navigation-bar": "~57.0.2", - "expo-router": "~57.0.18", - "expo-screen-capture": "~57.0.2", + "expo-router": "~57.0.21", + "expo-screen-capture": "~57.0.3", "expo-screen-orientation": "~57.0.2", - "expo-sharing": "~57.0.17", - "expo-splash-screen": "~57.0.8", - "expo-sqlite": "~57.0.2", + "expo-sharing": "~57.0.19", + "expo-splash-screen": "~57.0.9", + "expo-sqlite": "~57.0.3", "expo-status-bar": "~57.0.1", - "expo-system-ui": "~57.0.3", + "expo-system-ui": "~57.0.4", "react": "19.2.3", "react-dom": "19.2.3", "react-native": "0.86.3", @@ -2234,9 +2234,9 @@ } }, "node_modules/@expo-google-fonts/material-symbols": { - "version": "0.4.43", - "resolved": "https://registry.npmjs.org/@expo-google-fonts/material-symbols/-/material-symbols-0.4.43.tgz", - "integrity": "sha512-jJzgVcbkJnl48X5iBFNaL5CQHwoBElJapl8unc2Ri8DnyuBR+gRiuAD4gu3ESZjjo3sknIoYIwloOsWzKbLknQ==", + "version": "0.4.47", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/material-symbols/-/material-symbols-0.4.47.tgz", + "integrity": "sha512-5G4ObZlyGvDzx6g/+NC+RAMeeCc3dc0/HLu/llY5dYZUlNDYzaZWQZwPUzoTixf27riT8I7ur9mQKPYCPFDJzQ==", "license": "MIT AND Apache-2.0" }, "node_modules/@expo/code-signing-certificates": { @@ -2389,9 +2389,9 @@ "license": "MIT" }, "node_modules/@expo/fingerprint": { - "version": "0.20.12", - "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.20.12.tgz", - "integrity": "sha512-FIR5fkZYeFaLSowmjgyB6RPKl8AXeE8HuCBHHvyxK8UhOjpPfCAmzT4E7v2yub4qqDafKnfcOFCYxvpUEu+01w==", + "version": "0.20.13", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.20.13.tgz", + "integrity": "sha512-h1x+w+JpNRu88a/5SMZRzJs9YDGR/f7R8ApCr7OdenhqmJ00hFxQMzvxajDLL+1P2Y2g/ND0xksusqvBqWSW5Q==", "license": "MIT", "dependencies": { "@expo/env": "^2.4.3", @@ -2593,9 +2593,9 @@ } }, "node_modules/@expo/metro-file-map": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/@expo/metro-file-map/-/metro-file-map-57.0.2.tgz", - "integrity": "sha512-tb50nSIWwKpRufSkGuivOK0FbUxv1Uwqptb0SzFTk0bkmYmcy3gIwnCbOHTfmrQDVndRhPEiu2SYgh9Z0PCvGg==", + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/@expo/metro-file-map/-/metro-file-map-57.0.3.tgz", + "integrity": "sha512-1OXy+uPYY5uc7Tm4VBsd2NRn+3wHhqeqNuEO/Xo4kmYgv8FjYgUAc+bUXON9FpC2ikcLn4EVlGM9ce2exx9Mlg==", "license": "MIT", "dependencies": { "debug": "^4.3.4", @@ -3021,9 +3021,9 @@ } }, "node_modules/@expo/prebuild-config": { - "version": "57.0.15", - "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-57.0.15.tgz", - "integrity": "sha512-xTbWHroj0PDmlbqvmU+zF9ZZxveJkiuyiPoeRJYRGruFHebRAWnoTdw5S7d/UCzDBI8ropGGu9g2eb2nMxtvAw==", + "version": "57.0.16", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-57.0.16.tgz", + "integrity": "sha512-QA8oMZ7y70kjOzw+abhRl9uYC8Nu/abeUTHr0YVxb3pgIC14gc7w543bYtI+5gEDI3q55jKUViIauC76QvZN1w==", "license": "MIT", "dependencies": { "@expo/config": "~57.0.9", @@ -3033,7 +3033,7 @@ "@expo/json-file": "^11.0.1", "@react-native/normalize-colors": "0.86.3", "debug": "^4.3.1", - "expo-modules-autolinking": "~57.0.12", + "expo-modules-autolinking": "~57.0.13", "resolve-from": "^5.0.0", "semver": "^7.6.0" } @@ -3113,9 +3113,9 @@ "license": "MIT" }, "node_modules/@expo/ui": { - "version": "57.0.15", - "resolved": "https://registry.npmjs.org/@expo/ui/-/ui-57.0.15.tgz", - "integrity": "sha512-qNntEAbDEq0VGkAUMaopIZLJEZofQMDJNjx8YBngqeG3oZJKjpQFOSI8ui951NbN8nABzJ5Jd55SXdZKYWslDw==", + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/@expo/ui/-/ui-57.0.18.tgz", + "integrity": "sha512-9RkA26v0FSyHlkQCyavZrT8EzsALfkNHIFO5uC+IsAxzWzItdOWdy6asjpg1yaCvBEGMYkP17FUZxluhVbeleA==", "license": "MIT", "dependencies": { "sf-symbols-typescript": "^2.1.0", @@ -3142,9 +3142,9 @@ } }, "node_modules/@expo/xcpretty": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.4.tgz", - "integrity": "sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.5.tgz", + "integrity": "sha512-J3eL4n4h5QTwfD0SIz8OIk6/+sOL/hFZAMacgCM07UNlxBQfJipEpIC2AQxvGkbYeStByJ0TVhQAJo+DeNgaSQ==", "license": "BSD-3-Clause", "dependencies": { "@babel/code-frame": "^7.20.0", @@ -3413,43 +3413,6 @@ } } }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.23", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz", - "integrity": "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-focus-guards": "1.1.6", - "@radix-ui/react-focus-scope": "1.1.16", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-layout-effect": "1.1.4", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.7.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-direction": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.4.tgz", @@ -3465,33 +3428,6 @@ } } }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz", - "integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-effect-event": "0.0.5" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz", @@ -3507,31 +3443,6 @@ } } }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz", - "integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-id": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz", @@ -3550,30 +3461,6 @@ } } }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.17", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz", - "integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-presence": { "version": "1.1.10", "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.10.tgz", @@ -5483,9 +5370,9 @@ } }, "node_modules/babel-preset-expo": { - "version": "57.0.10", - "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-57.0.10.tgz", - "integrity": "sha512-08bt6bqMZFoQuWO9gkt0EXotbqKHimELFGa1LlKJvY89iKsi4S0FJSFBFJ4pn9NZvofet48HIjYDQ0SZJ7bNrg==", + "version": "57.0.11", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-57.0.11.tgz", + "integrity": "sha512-R0NouDI3nzQUsjBh5TUJSDXLmuVzE2bp2YE0ywJkKxzrdWVjShpAlZMBuDeOQy6iKGB6ZCCvMqbQvpqgNMJ7iw==", "license": "MIT", "dependencies": { "@babel/generator": "^7.20.5", @@ -5534,7 +5421,7 @@ "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", - "expo-widgets": "^57.0.16", + "expo-widgets": "^57.0.18", "react-refresh": ">=0.14.0 <1.0.0" }, "peerDependenciesMeta": { @@ -7327,31 +7214,31 @@ } }, "node_modules/expo": { - "version": "57.0.19", - "resolved": "https://registry.npmjs.org/expo/-/expo-57.0.19.tgz", - "integrity": "sha512-oIoAIisim1DwS2Zjp0rcEY9cfcq1wU6KpkBfwwFhJWI5YHV6i/aIzTUMX+uf0Q0CD6AvMls7IZVh34o27NjaJA==", + "version": "57.0.22", + "resolved": "https://registry.npmjs.org/expo/-/expo-57.0.22.tgz", + "integrity": "sha512-YWUGqWtchsRQzcbU+Iqqt/1kFbZ9Pp3/eg+UenINahNt2RIaDElFJFFWLD1Yfex6WnBm6ESSE8h0/ja28hRqZg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "^57.0.21", + "@expo/cli": "^57.0.24", "@expo/config": "~57.0.9", "@expo/config-plugins": "~57.0.9", "@expo/devtools": "~57.0.1", "@expo/dom-webview": "~57.0.1", - "@expo/fingerprint": "^0.20.12", + "@expo/fingerprint": "^0.20.13", "@expo/local-build-cache-provider": "^57.0.8", "@expo/log-box": "^57.0.4", "@expo/metro": "~56.0.2", "@expo/metro-config": "~57.0.12", "@ungap/structured-clone": "^1.3.0", - "babel-preset-expo": "~57.0.10", - "expo-asset": "~57.0.16", - "expo-constants": "~57.0.17", - "expo-file-system": "~57.0.6", - "expo-font": "~57.0.3", - "expo-keep-awake": "~57.0.1", - "expo-modules-autolinking": "~57.0.12", - "expo-modules-core": "~57.0.15", + "babel-preset-expo": "~57.0.11", + "expo-asset": "~57.0.17", + "expo-constants": "~57.0.18", + "expo-file-system": "~57.0.7", + "expo-font": "~57.0.4", + "expo-keep-awake": "~57.0.2", + "expo-modules-autolinking": "~57.0.13", + "expo-modules-core": "~57.0.18", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.2" @@ -7389,13 +7276,13 @@ } }, "node_modules/expo-asset": { - "version": "57.0.16", - "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-57.0.16.tgz", - "integrity": "sha512-IBRfQdW3iFT+GOBERMZLZM1MUNyrjMgMskuD0elVZ1ae44858UFlTJkHO3f8vi+u5zuv7O7KofsiN8NMG/uWzw==", + "version": "57.0.17", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-57.0.17.tgz", + "integrity": "sha512-qSdWZBSfEg06o3GJMwcj36tw0vXkB6eYjqkQistWmyJkHxhUOKnsKJnev6OraXxLdoI+KOd1+qgp/ENx8gcqYA==", "license": "MIT", "dependencies": { "@expo/image-utils": "^0.11.5", - "expo-constants": "~57.0.17" + "expo-constants": "~57.0.18" }, "peerDependencies": { "expo": "*", @@ -7431,9 +7318,9 @@ } }, "node_modules/expo-build-properties": { - "version": "57.0.16", - "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-57.0.16.tgz", - "integrity": "sha512-snEQKIn/sMEAFUc8x2aQTQa/rzJbfjsuLJ9YcGUh5iCN65nid7R2V8J3PKyMUFPVEST+cDNf8WDlgN8jOuveXw==", + "version": "57.0.17", + "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-57.0.17.tgz", + "integrity": "sha512-+qA5we2h1Gpnd24RGCR1amfSx7Mtf8glZ0jA5bbe1Nfdw9NdAIl+HPUqU7xyOUDKD0JWsHh9ap6yJG/jTs0tvA==", "license": "MIT", "dependencies": { "@expo/schema-utils": "^57.0.2", @@ -7457,9 +7344,9 @@ } }, "node_modules/expo-clipboard": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-57.0.1.tgz", - "integrity": "sha512-HWICri4+1ao7S6QEfcorxVumXDiDnx1guGGewjZgGJWLGxFYs0RgH8ujBs+lkTzBkMmlwADaWSlaesR+nDJt5Q==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-57.0.2.tgz", + "integrity": "sha512-VB4Au8X/RbvJKUtJk+87vdtveWSNEa5RzY3ooeO6VNF7Rd49RbQXZOu3/TfEW9p7mU8TCfyTvjyCiAUwSoSJ4w==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -7468,9 +7355,9 @@ } }, "node_modules/expo-constants": { - "version": "57.0.17", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.17.tgz", - "integrity": "sha512-cPWYBKN1SEbg2lXg2f8VkePJqGZrJPLvVdQDCTfbFu9sQHO1M31Y1zILReUuGnmt/VKeUz40ze579vR00xGu/A==", + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.18.tgz", + "integrity": "sha512-cLDwDOniPfuCZPHNY++cAY2ZkK97u5aobbBvilPK2LLmaWxR4ZpD31LWUIzUDLrwMPxLjmh1uURnbeYEf0Mivw==", "license": "MIT", "dependencies": { "@expo/env": "~2.4.3" @@ -7481,30 +7368,30 @@ } }, "node_modules/expo-dev-client": { - "version": "57.0.18", - "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-57.0.18.tgz", - "integrity": "sha512-cT+6iO4rRoguIxeONAPHF2wbAlc002tZya2M3xHlc6EWKptjsAL2Vr+kagYdLH/4vtLX7XKhWvOzaBf+rQpRFg==", + "version": "57.0.19", + "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-57.0.19.tgz", + "integrity": "sha512-7giMK6BLL685GECHem2UAQvS473ImZLi5l+Q5tq+XSyv6I9UNVPs0p07mKwgBzq8z7DR3d4nTl702ziFxTjO3Q==", "license": "MIT", "dependencies": { - "expo-dev-launcher": "~57.0.19", + "expo-dev-launcher": "~57.0.20", "expo-dev-menu": "~57.0.18", "expo-dev-menu-interface": "~57.0.0", - "expo-manifests": "~57.0.1", - "expo-updates-interface": "~57.0.1" + "expo-manifests": "~57.0.2", + "expo-updates-interface": "~57.0.2" }, "peerDependencies": { "expo": "*" } }, "node_modules/expo-dev-launcher": { - "version": "57.0.19", - "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-57.0.19.tgz", - "integrity": "sha512-IF/EJ3tcHqiyfBb5VtpAU3upBXRVTFVuVoWqEzrkZCesuMi35td4yQFvPtqXbMceaEErgFyiyxhW+L6AXVYapA==", + "version": "57.0.20", + "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-57.0.20.tgz", + "integrity": "sha512-F6oAHaDn9j3L/gyMGE+OalriX6PHZWnZLxpN5jc6crTrp8f6hSwGhmsHpAvdOzijfMjyi3R2UkcISFsCIIQYFA==", "license": "MIT", "dependencies": { "@expo/schema-utils": "^57.0.2", "expo-dev-menu": "~57.0.18", - "expo-manifests": "~57.0.1" + "expo-manifests": "~57.0.2" }, "peerDependencies": { "expo": "*", @@ -7547,9 +7434,9 @@ } }, "node_modules/expo-file-system": { - "version": "57.0.6", - "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-57.0.6.tgz", - "integrity": "sha512-pm8PMYEW6BnVOCBJ7df9FcDmQtE1tqImuYphlfYe1ipQRLYtdCayRczJcbKIsnB3mqEyp4gC2gWmMbsAsAOjVg==", + "version": "57.0.7", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-57.0.7.tgz", + "integrity": "sha512-1vkZRadOsIputFDBcclqBa1pO3iXOO6iIsdqJipQWw4V5TSnWgmRTuOF7ro8IzrVue+PHbum++KCG3Tawem4cg==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -7557,9 +7444,9 @@ } }, "node_modules/expo-font": { - "version": "57.0.3", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.3.tgz", - "integrity": "sha512-kiVUnc2A8vAvO2FfDJTsQa5BwmY+PAkof/1wRb5MOkcX1jtiaSTwz9gCUAyscMBFLundZDmZrLy1P7LZVC+NvA==", + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.4.tgz", + "integrity": "sha512-7WOMC2oA6xCfOm8bbofqWn2bIqyWFm7YLEnpc/gA1MJH0Ll0TfT/3+CqRkoW2eNRWMS8sxrz5WukUmSvmNquHA==", "license": "MIT", "dependencies": { "fontfaceobserver": "^2.1.0" @@ -7571,9 +7458,9 @@ } }, "node_modules/expo-glass-effect": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/expo-glass-effect/-/expo-glass-effect-57.0.1.tgz", - "integrity": "sha512-m/n8maxqNcHk6ZDhuqXBfD5Kt1Iz3M8xykVgdB0iSCIXvF70IqWXmQhX8Psswhrp8eZ+3r0mAD0Jh/2gFA3QaA==", + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-glass-effect/-/expo-glass-effect-57.0.3.tgz", + "integrity": "sha512-aTh2J5eCxf+rSRMBJTnP8Ib5/k8DYFVDuEX1xqesN9F9aqTXocwMv/aQRVBNUs/iogDWhHIJz2pN97IsrrTcoA==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -7582,15 +7469,15 @@ } }, "node_modules/expo-json-utils": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-57.0.1.tgz", - "integrity": "sha512-cgTe1NqzQdYs/WN+3nIY5IZg8s0pb0xaTUbhYvxQDn137GbwRfHoGM2se3m3Vsl4Qu+B9G4RPEK5WJDEU2Do7g==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-57.0.2.tgz", + "integrity": "sha512-9kYZECLKE3pYZQs+kt3+ggY83Lfryog9/UEo3HJKGcHUZeKKtlFBIPFjI4LzREubsvjP7AsvG0FdEX9EquIoAQ==", "license": "MIT" }, "node_modules/expo-keep-awake": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-57.0.1.tgz", - "integrity": "sha512-28lkFImeXTS+bhAjuCFV7w7tW5bXg27BJVrxv+nC/nyYa86qEa0oFeHwqol6ha5k4pdVDQgBF09GM4A1k76Ssg==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-57.0.2.tgz", + "integrity": "sha512-GqgH746wtJImmsbyHmCQoi7cOslKuWQBbJHXr53S35Bpf5UvxCAztvnitUEd7D0QvFN2rvkOhylbZpgZZfBLlQ==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -7598,9 +7485,9 @@ } }, "node_modules/expo-linear-gradient": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-57.0.1.tgz", - "integrity": "sha512-CpS8eMqoIWcHVGKV66zbDvzotCw9qYp3f8CuI9N+h1LaO0tMLUzBpkhAKePUsXlpN3yolYlHFSPkfVZ/uSh+iA==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-57.0.2.tgz", + "integrity": "sha512-eGNSfcbdXYvw0B/TQ3nmXKQgj0jLUi3EgsXGlvI79rlXg5RR5dQTkY2yqkf7BQDM3PMd3tqBMZdsLhvBqSUaMg==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -7609,12 +7496,12 @@ } }, "node_modules/expo-linking": { - "version": "57.0.9", - "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-57.0.9.tgz", - "integrity": "sha512-TQJe3NsnpZXApBg1n6DKaZ4TNhYm+iYWq7W9rTp+G44IBMZSUcI8ba+ffYC/LMY1qw+95AuBPIF1zTx1NQoTXw==", + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-57.0.10.tgz", + "integrity": "sha512-RzRi4l4pIYzjgoCJKnqkO+lUI+M2YX6qgcMIQkIbLAXdcWrykBoKYwHGlmAkdFHQm89GaYcq329yfxG+c1hv8w==", "license": "MIT", "dependencies": { - "expo-constants": "~57.0.17", + "expo-constants": "~57.0.18", "invariant": "^2.2.4" }, "peerDependencies": { @@ -7623,9 +7510,9 @@ } }, "node_modules/expo-local-authentication": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/expo-local-authentication/-/expo-local-authentication-57.0.2.tgz", - "integrity": "sha512-8K4zcrQ5wZkRS1rwEWY8qHbeGVMNh35e9D1VTVKlMHz1O47itW+pW6iBVuqwGFLozN4fRBeEDQH8hu9Gt58YuQ==", + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-local-authentication/-/expo-local-authentication-57.0.3.tgz", + "integrity": "sha512-1oQCBKz8JOpai+Zp+Z2RkBFIi2CHHWLSJk/pjvT9VEyf8nPFslo4kt1ZlQvtJ4rupbKNCmxqKfYr8Mlo8nJEug==", "license": "MIT", "dependencies": { "invariant": "^2.2.4" @@ -7635,21 +7522,21 @@ } }, "node_modules/expo-manifests": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-57.0.1.tgz", - "integrity": "sha512-qB/mDG2dYdl+EvUeQuqP8KFYCFgFCQjJYdWIHo8SFBgDzMYmdF286DFY2M1M9Okr99wkb5M4tgA3aCcwv3aEQA==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-57.0.2.tgz", + "integrity": "sha512-pPIIcKR73OShwlWMg8H90WRzKUd2krDdKlKAwuQV1FtUwE7H3hQEFw0ePFQY9yFoGMF/77ryYwNKfI5umMcCog==", "license": "MIT", "dependencies": { - "expo-json-utils": "~57.0.1" + "expo-json-utils": "~57.0.2" }, "peerDependencies": { "expo": "*" } }, "node_modules/expo-modules-autolinking": { - "version": "57.0.12", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-57.0.12.tgz", - "integrity": "sha512-Q8KAlq37nLKsQ+HsS9NpQVpd5jCgqtu694TDUNHBUBpV9ViD82mRBh8Uug/h68RG9xnLS+kuL4nYaCuFRghHjg==", + "version": "57.0.13", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-57.0.13.tgz", + "integrity": "sha512-Hj5NjZRlfccazhKab+wK19leRVUr1Y/PUERaRvegIbUSkq4GVxKq6lU9QHlKQyC16MdD/VS4iwsiLivB4o7lvQ==", "license": "MIT", "dependencies": { "@expo/require-utils": "^57.0.5", @@ -7662,13 +7549,13 @@ } }, "node_modules/expo-modules-core": { - "version": "57.0.15", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-57.0.15.tgz", - "integrity": "sha512-HBxPXsx3eVLLRjAY57/8ghKDWIxjaEbluKKYFIq1OHPJC85ZfHsawwc0SOU4Z/qu+mdLz7Pwt5IkkWimeNSH5A==", + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-57.0.18.tgz", + "integrity": "sha512-ovB7C+GVQTlKAOIsOIHJVVXN9Mn0ljf2SYBS+afrRaGqq+HZEn1D3o+HReIVeH1NjCn/xDBb7I4HjldHs6luZA==", "license": "MIT", "dependencies": { "@expo/expo-modules-macros-plugin": "0.6.1", - "expo-modules-jsi": "~57.0.7", + "expo-modules-jsi": "~57.1.0", "invariant": "^2.2.4" }, "peerDependencies": { @@ -7683,9 +7570,9 @@ } }, "node_modules/expo-modules-jsi": { - "version": "57.0.7", - "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-57.0.7.tgz", - "integrity": "sha512-/GOrTFPnCfg7+m6M1yOSEKNeNdHBCm0ju6aJ4XHlSmtE02nb7mWh1Cs6QsK2eB5Rz7hjbb356Nd7UimsFvN7Vg==", + "version": "57.1.0", + "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-57.1.0.tgz", + "integrity": "sha512-a5ckeHfnbYfonhcHGkM0EU/a0Keh+/OufXy/HyFS+spr5Ib0N4Oh1ZsSYFQhp5xdOUFkVofKRhfH+VmcccIIpA==", "license": "MIT", "peerDependencies": { "react-native": "*" @@ -7706,15 +7593,15 @@ } }, "node_modules/expo-router": { - "version": "57.0.18", - "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-57.0.18.tgz", - "integrity": "sha512-Mj4uv88J6QQLC46GQlCNIwH6kd1685x52RdcQuGIGt5nZk4axfRJOjd0zqXZQzSqOR8bbkuufHMM+dYKtCdVvA==", + "version": "57.0.21", + "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-57.0.21.tgz", + "integrity": "sha512-r7UDLZU0gtVm8FW4nv2pxSl9TDhKlf2shcBbfp1T9STXJ3xYl9llLH701qQkICuXqqt3vGpOZ57GXC1ioVWg4g==", "license": "MIT", "dependencies": { "@expo/log-box": "^57.0.4", "@expo/metro-runtime": "^57.0.15", "@expo/schema-utils": "^57.0.2", - "@expo/ui": "^57.0.15", + "@expo/ui": "^57.0.18", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-native-masked-view/masked-view": "^0.3.2", @@ -7722,12 +7609,12 @@ "color": "^4.2.3", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "expo-glass-effect": "^57.0.1", + "expo-glass-effect": "^57.0.3", "expo-server": "^57.0.3", - "expo-symbols": "^57.0.2", + "expo-symbols": "^57.0.3", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", - "nanoid": "^3.3.8", + "nanoid": "^3.3.18", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-is": "^19.1.0", @@ -7744,8 +7631,8 @@ "@expo/metro-runtime": "^57.0.15", "@testing-library/react-native": ">= 13.2.0", "expo": "*", - "expo-constants": "^57.0.17", - "expo-linking": "^57.0.9", + "expo-constants": "^57.0.18", + "expo-linking": "^57.0.10", "react": "*", "react-dom": "*", "react-native": "*", @@ -7778,9 +7665,9 @@ } }, "node_modules/expo-screen-capture": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/expo-screen-capture/-/expo-screen-capture-57.0.2.tgz", - "integrity": "sha512-Ww8LFdSXuW7YeHc6/DwZd5tOEUqHAsOy4hLrfBxu99pbv+14sD9Lh0ueZeutg4QVktI+u2XJqFjMqyJ0b/5yxA==", + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-screen-capture/-/expo-screen-capture-57.0.3.tgz", + "integrity": "sha512-EpTd6tBgX2nWKJUvYDIrnsC2xWGJnlOLqN48EzLwPTQlbbwDUeWwt+4RDZOyFkWCa67XiUbrzIEOJApNBVZSow==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -7807,9 +7694,9 @@ } }, "node_modules/expo-sharing": { - "version": "57.0.17", - "resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-57.0.17.tgz", - "integrity": "sha512-p2B4SMeNsOv6hm1NkrxRlncjwu9mmLfi0drLaEyX13Rxn4DdDFPhuaezpOK7XLogTsmWGpfR46uq6oHMvSxbfA==", + "version": "57.0.19", + "resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-57.0.19.tgz", + "integrity": "sha512-lZ9chd/kxalZkMaJnPxW6dEpj7hnlrikesiEV9KLS99VKgkfLgH+/pFvIfk0YwGJ1b1/eLGcZ7OfJ2jjSgFpNA==", "license": "MIT", "dependencies": { "@expo/config-plugins": "^57.0.9", @@ -7823,9 +7710,9 @@ } }, "node_modules/expo-splash-screen": { - "version": "57.0.8", - "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-57.0.8.tgz", - "integrity": "sha512-BEsrKg4niYBZa5AFzWRyGqxA4ZemtBOPwbCy+C336iGYYPuZYLEgWJGmm2xD1gRfCdrM/TP+l2ONd86Zvk3KyA==", + "version": "57.0.9", + "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-57.0.9.tgz", + "integrity": "sha512-7cKDn7uBwg0RkcmY015/5j9st4msWJ4zQiPmQdVZoppW3cFSbv05n7xhM6CjUU466Tx4VRTqDF21HuIHkmnEtA==", "license": "MIT", "dependencies": { "@expo/config-plugins": "~57.0.9", @@ -7837,9 +7724,9 @@ } }, "node_modules/expo-sqlite": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-57.0.2.tgz", - "integrity": "sha512-5KVbT7BQFZlIcQBXKWvwBERK3ODF6PSqct27GQKukZzAjsx2B97R+mwtYqrTUtUbw71VJrQrdr9Yl2OWYC7UpA==", + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-57.0.3.tgz", + "integrity": "sha512-gbu9Nwm76DNpSK+MEhCjjjF3/EMyFE96IEDSlfO9jPiF4q48a7bef5EXnWVrwW8rvqCZKYAfSGqSpYNhhhpgIg==", "license": "MIT", "dependencies": { "await-lock": "^2.2.2" @@ -7862,9 +7749,9 @@ } }, "node_modules/expo-symbols": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-57.0.2.tgz", - "integrity": "sha512-qZ0iqOflm5lZGwRsQ5Y8sDksw3GAUKwHSX1bJBoocXf7gu14vafIXXYWte+JT9VfXAUGyKodJhLHP/GoOrcNWg==", + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-57.0.3.tgz", + "integrity": "sha512-uuK5yHLVR7kExUCrO/ItBvp/kp1maQ9Nkb6KvNy5ZUQnN0NMKwuhJ4GvbfS9N3ACmvCjTT4gKvg4yH5UuKIYNA==", "license": "MIT", "dependencies": { "@expo-google-fonts/material-symbols": "^0.4.1", @@ -7878,9 +7765,9 @@ } }, "node_modules/expo-system-ui": { - "version": "57.0.3", - "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-57.0.3.tgz", - "integrity": "sha512-3N3BoagGojEvQw0h7kL0Lvv2LrVjqEvODSNS+Nc9lj/kzaTaVx4K1HI8qqxeALMf5jui3rLP2b3Ai2pXotoNuA==", + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-57.0.4.tgz", + "integrity": "sha512-z//rxQJzhTNA1PcKrUtWmrd21jAS3nEDu1b0n8B/7LTTR933OcsZYP1HnbaZifuo2ZH/h7nce2Ow61WZ1Ig2bg==", "license": "MIT", "dependencies": { "@react-native/normalize-colors": "0.86.3", @@ -7898,18 +7785,18 @@ } }, "node_modules/expo-updates-interface": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-57.0.1.tgz", - "integrity": "sha512-+LUWwJ0gf/TEKMVdQAw/Gjih4dvrk+URgy24X9qEGKuuMDZqjBRm9T4yQyBVALGL5TTdPUaB6ILxx3lshm3pwQ==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-57.0.2.tgz", + "integrity": "sha512-x3SA5toiHZEkW+5oeNdUM1Rvt6M3ExegQsSwS3Z1+S9gn9utGYTGBkb8MBQivhjIZiRlQYDIhauxA8kySQEWtQ==", "license": "MIT", "peerDependencies": { "expo": "*" } }, "node_modules/expo/node_modules/@expo/cli": { - "version": "57.0.21", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-57.0.21.tgz", - "integrity": "sha512-CkcgAOsp1KkNRENXWfyr/esIwgFtiHosKECWZ0QQl2nFOUEQlyjWXAZ6uTCMnbHLonVnPMZpXTkHZNw3gtanFw==", + "version": "57.0.24", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-57.0.24.tgz", + "integrity": "sha512-CCBkvhPgAcrzJQ3daYbyOD6YuqKKkvOIyUfAbsUIvlpLomIlocYxFHYdmaC/KHqfCsbGFYSV/QKTSYshhSFNEA==", "license": "MIT", "dependencies": { "@expo/code-signing-certificates": "^0.0.6", @@ -7923,11 +7810,11 @@ "@expo/log-box": "^57.0.4", "@expo/metro": "~56.0.2", "@expo/metro-config": "~57.0.12", - "@expo/metro-file-map": "^57.0.2", + "@expo/metro-file-map": "^57.0.3", "@expo/osascript": "^2.7.1", "@expo/package-manager": "^1.13.1", "@expo/plist": "^0.8.1", - "@expo/prebuild-config": "^57.0.15", + "@expo/prebuild-config": "^57.0.16", "@expo/require-utils": "^57.0.5", "@expo/router-server": "^57.0.9", "@expo/schema-utils": "^57.0.2", @@ -14164,6 +14051,119 @@ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, + "node_modules/vaul/node_modules/@radix-ui/react-dialog": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz", + "integrity": "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-dismissable-layer": "1.1.19", + "@radix-ui/react-focus-guards": "1.1.6", + "@radix-ui/react-focus-scope": "1.1.16", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-portal": "1.1.17", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-slot": "1.3.3", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz", + "integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-effect-event": "0.0.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz", + "integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-portal": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz", + "integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/vlq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", diff --git a/package.json b/package.json index e485343b..97354ab3 100644 --- a/package.json +++ b/package.json @@ -24,24 +24,24 @@ "@shopify/flash-list": "2.0.2", "babel-plugin-inline-import": "^3.0.0", "drizzle-orm": "^0.45.2", - "expo": "~57.0.19", - "expo-build-properties": "~57.0.16", - "expo-clipboard": "~57.0.1", + "expo": "~57.0.22", + "expo-build-properties": "~57.0.17", + "expo-clipboard": "~57.0.2", "expo-constants": "~57.0.3", - "expo-dev-client": "~57.0.18", + "expo-dev-client": "~57.0.19", "expo-file-system": "~57.0.0", - "expo-linear-gradient": "~57.0.1", - "expo-linking": "~57.0.9", - "expo-local-authentication": "~57.0.2", + "expo-linear-gradient": "~57.0.2", + "expo-linking": "~57.0.10", + "expo-local-authentication": "~57.0.3", "expo-navigation-bar": "~57.0.2", - "expo-router": "~57.0.18", - "expo-screen-capture": "~57.0.2", + "expo-router": "~57.0.21", + "expo-screen-capture": "~57.0.3", "expo-screen-orientation": "~57.0.2", - "expo-sharing": "~57.0.17", - "expo-splash-screen": "~57.0.8", - "expo-sqlite": "~57.0.2", + "expo-sharing": "~57.0.19", + "expo-splash-screen": "~57.0.9", + "expo-sqlite": "~57.0.3", "expo-status-bar": "~57.0.1", - "expo-system-ui": "~57.0.3", + "expo-system-ui": "~57.0.4", "react": "19.2.3", "react-dom": "19.2.3", "react-native": "0.86.3", From b90417eb8f878fe9f60c25d82c58e797a73bf5a6 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Sat, 12 Sep 2026 22:23:33 +0530 Subject: [PATCH 08/12] refactor: expo sqlite native database access Signed-off-by: Jeel Dobariya --- src/app/(tabs)/(password-manager)/index.tsx | 13 +- .../(password-manager)/password-details.tsx | 10 +- .../(password-manager)/save-password.tsx | 9 +- src/app/(tabs)/(settings)/data-recovery.tsx | 22 +- .../(settings)/get-back-passwords.android.tsx | 12 +- src/app/(tabs)/(settings)/settings.tsx | 12 +- src/app/_layout.tsx | 6 +- src/db/provider.tsx | 210 ++++++++++++++---- src/libs/withSQLiteDatabase.ts | 28 +++ 9 files changed, 231 insertions(+), 91 deletions(-) create mode 100644 src/libs/withSQLiteDatabase.ts diff --git a/src/app/(tabs)/(password-manager)/index.tsx b/src/app/(tabs)/(password-manager)/index.tsx index c3abcc2e..51307e69 100644 --- a/src/app/(tabs)/(password-manager)/index.tsx +++ b/src/app/(tabs)/(password-manager)/index.tsx @@ -1,12 +1,12 @@ import PasswordItemCard from "@/components/PasswordItemCard"; import Text from "@/components/Text"; +import { useDrizzleDatabase } from "@/db/provider"; import { passwords } from "@/db/schema"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; import { FlashList } from "@shopify/flash-list"; import { eq } from "drizzle-orm"; -import { drizzle, useLiveQuery } from "drizzle-orm/expo-sqlite"; +import { useLiveQuery } from "drizzle-orm/expo-sqlite"; import { router, Stack } from "expo-router"; -import { useSQLiteContext } from "expo-sqlite"; import { useMemo, useState } from "react"; import { Alert, Pressable } from "react-native"; import { FAB, IconButton, useTheme } from "react-native-paper"; @@ -21,11 +21,10 @@ export default function LoadPasswordScreen() { const theme = useTheme(); - const db = useSQLiteContext(); - const drizzleDb = drizzle(db); + const db = useDrizzleDatabase(); const { data: passwordList = [] } = useLiveQuery( - drizzleDb.select().from(passwords), + db.select().from(passwords), [refreshKey], ); @@ -66,9 +65,7 @@ export default function LoadPasswordScreen() { { text: "Delete", onPress: async () => { - await drizzleDb - .delete(passwords) - .where(eq(passwords.id, password.id)); + await db.delete(passwords).where(eq(passwords.id, password.id)); }, style: "destructive", }, diff --git a/src/app/(tabs)/(password-manager)/password-details.tsx b/src/app/(tabs)/(password-manager)/password-details.tsx index c7034380..97932c0e 100644 --- a/src/app/(tabs)/(password-manager)/password-details.tsx +++ b/src/app/(tabs)/(password-manager)/password-details.tsx @@ -3,6 +3,7 @@ import PasswordFormCard, { usePasswordForm, } from "@/components/PasswordFormCard"; import { useToast } from "@/contexts/ToastContext"; +import { useDrizzleDatabase } from "@/db/provider"; import { passwords } from "@/db/schema"; import { getScreenShotSecureScreen } from "@/libs/screenshot_prevention"; @@ -10,10 +11,8 @@ import { formatDate } from "@passcodes/passalgo"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; import { eq } from "drizzle-orm"; -import { drizzle } from "drizzle-orm/expo-sqlite"; import { Href, router, useLocalSearchParams } from "expo-router"; import { usePreventRemove } from "expo-router/react-navigation"; -import { useSQLiteContext } from "expo-sqlite"; import { useEffect, useState } from "react"; import { Keyboard, ScrollView, TextInput } from "react-native"; @@ -24,8 +23,7 @@ import { SafeAreaView } from "react-native-safe-area-context"; export default function PasswordDetailsScreen() { const { id } = useLocalSearchParams(); - const db = useSQLiteContext(); - const drizzleDb = drizzle(db); + const db = useDrizzleDatabase(); const { state, setState, updateField } = usePasswordForm(); const [isEditing, setIsEditing] = useState(false); @@ -48,7 +46,7 @@ export default function PasswordDetailsScreen() { } async function loadAndRefreshPassword() { - const result = await drizzleDb + const result = await db .select() .from(passwords) .where(eq(passwords.id, Number(id))); @@ -77,7 +75,7 @@ export default function PasswordDetailsScreen() { unfocusAllFields(); try { - await drizzleDb + await db .update(passwords) .set({ ...state, updatedAt: new Date().toISOString() }) .where(eq(passwords.id, Number(id))); diff --git a/src/app/(tabs)/(password-manager)/save-password.tsx b/src/app/(tabs)/(password-manager)/save-password.tsx index a721a9bd..f53ec0c5 100644 --- a/src/app/(tabs)/(password-manager)/save-password.tsx +++ b/src/app/(tabs)/(password-manager)/save-password.tsx @@ -1,12 +1,11 @@ import FormTextField from "@/components/FormTextField"; import SecureTextField from "@/components/SecureTextField"; import { useToast } from "@/contexts/ToastContext"; +import { useDrizzleDatabase } from "@/db/provider"; import { passwords } from "@/db/schema"; import { getScreenShotSecureScreen } from "@/libs/screenshot_prevention"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; -import { drizzle } from "drizzle-orm/expo-sqlite"; import { router } from "expo-router"; -import { useSQLiteContext } from "expo-sqlite"; import { useState } from "react"; import { Alert, ScrollView, View } from "react-native"; import { Button } from "react-native-paper"; @@ -19,8 +18,7 @@ export default function SavePasswordScreen() { let [url, setUrl] = useState(""); let [notes, setNotes] = useState(""); - const db = useSQLiteContext(); - const drizzleDb = drizzle(db); + const db = useDrizzleDatabase(); const { showToast } = useToast(); @@ -104,8 +102,7 @@ export default function SavePasswordScreen() { return; } - drizzleDb - .insert(passwords) + db.insert(passwords) .values({ domain, username, diff --git a/src/app/(tabs)/(settings)/data-recovery.tsx b/src/app/(tabs)/(settings)/data-recovery.tsx index 4b980b55..72bb0e11 100644 --- a/src/app/(tabs)/(settings)/data-recovery.tsx +++ b/src/app/(tabs)/(settings)/data-recovery.tsx @@ -1,7 +1,7 @@ import ScreenHeading from "@/components/ScreenHeading"; import Text from "@/components/Text"; import dataRecoveryFromTestDB from "@/libs/data_recovery_test_db_mess"; -import * as SQLite from "expo-sqlite"; +import { withSQLiteDatabase } from "@/libs/withSQLiteDatabase"; import { useEffect, useState } from "react"; import { SafeAreaView } from "react-native-safe-area-context"; @@ -10,16 +10,19 @@ type MigrationResult = { message: string; }; +const OLD_DATABASE_NAME = "test2.db"; + export default function DataRecoveryScreen() { - const expoDb = SQLite.useSQLiteContext(); const [result, setResult] = useState({ state: "Running", - message: "please wait...", + message: "Please wait...", }); useEffect(() => { async function runMigration() { - await dataRecoveryFromTestDB(expoDb); + await withSQLiteDatabase(OLD_DATABASE_NAME, async (expoDb) => { + await dataRecoveryFromTestDB(expoDb); + }); } runMigration() @@ -29,10 +32,10 @@ export default function DataRecoveryScreen() { message: "Done!! PROBLEM FIXED", }); }) - .catch((e) => { + .catch((error) => { setResult({ state: "Error", - message: e.toString(), + message: error instanceof Error ? error.message : String(error), }); }); }, []); @@ -50,7 +53,12 @@ export default function DataRecoveryScreen() { {result.state} - + + {result.message} diff --git a/src/app/(tabs)/(settings)/get-back-passwords.android.tsx b/src/app/(tabs)/(settings)/get-back-passwords.android.tsx index 22282b56..48e8c0e7 100644 --- a/src/app/(tabs)/(settings)/get-back-passwords.android.tsx +++ b/src/app/(tabs)/(settings)/get-back-passwords.android.tsx @@ -1,7 +1,8 @@ import ScreenHeading from "@/components/ScreenHeading"; import Text from "@/components/Text"; +import { DEFAULT_DATABASE_NAME } from "@/db/provider"; import roomDrizzleMigration from "@/libs/room_drizzle_migration"; -import * as SQLite from "expo-sqlite"; +import { withSQLiteDatabase } from "@/libs/withSQLiteDatabase"; import AsyncStorage from "expo-sqlite/kv-store"; import { useEffect, useState } from "react"; import { Button } from "react-native"; @@ -21,8 +22,6 @@ export default function GetBackPasswordsScreen() { isError: false, }); - const expoDb = SQLite.useSQLiteContext(); - useEffect(() => { async function runMigration() { try { @@ -50,7 +49,12 @@ export default function GetBackPasswordsScreen() { }); // Run migration - const result = await roomDrizzleMigration(expoDb); + const result = await withSQLiteDatabase( + DEFAULT_DATABASE_NAME, + async (expoDb) => { + return await roomDrizzleMigration(expoDb); + }, + ); await AsyncStorage.setItem(MIGRATION_KEY, MIGRATION_STATUS.SUCCESS); diff --git a/src/app/(tabs)/(settings)/settings.tsx b/src/app/(tabs)/(settings)/settings.tsx index fbe6283b..75f82b7f 100644 --- a/src/app/(tabs)/(settings)/settings.tsx +++ b/src/app/(tabs)/(settings)/settings.tsx @@ -22,14 +22,13 @@ import { toggleScreenshotPreventionFeature, } from "@/libs/screenshot_prevention"; import { FontAwesome6 } from "@react-native-vector-icons/fontawesome6"; -import { drizzle } from "drizzle-orm/expo-sqlite"; import { LinearGradient } from "expo-linear-gradient"; -import { useSQLiteContext } from "expo-sqlite"; import { useState } from "react"; import { Alert, ScrollView } from "react-native"; import { Card, Divider, List, Switch, useTheme } from "react-native-paper"; import { SafeAreaView } from "react-native-safe-area-context"; +import { useDrizzleDatabase } from "@/db/provider"; import PasscodesAutofillServiceModule from "../../../../modules/passcodes-autofill-service/src/PasscodesAutofillServiceModule"; export default function SettingsScreen() { @@ -50,15 +49,14 @@ export default function SettingsScreen() { ); const theme = useTheme(); - let db = useSQLiteContext(); - const drizzleDb = drizzle(db); + let db = useDrizzleDatabase(); async function handleImportPasswords() { let content = await getCSVPasswordString(); let importPasswordList: PasswordCSVFormat[] = convertRawCSVToPasswords(content); - drizzleDb.transaction((tx) => { + db.transaction((tx) => { importPasswordList.forEach((importablePassword) => { tx.insert(passwords) .values({ @@ -74,9 +72,7 @@ export default function SettingsScreen() { } async function handleExportPasswords() { - const result: PasswordCSVFormat[] = await drizzleDb - .select() - .from(passwords); + const result: PasswordCSVFormat[] = await db.select().from(passwords); let content = await getGooglePasswordsCSVContent(result); sharePasswordAsCSV(content); diff --git a/src/app/_layout.tsx b/src/app/_layout.tsx index 8a8e4095..2e4ddf75 100644 --- a/src/app/_layout.tsx +++ b/src/app/_layout.tsx @@ -1,6 +1,6 @@ import ScreenHeading from "@/components/ScreenHeading"; import { ToastProvider } from "@/contexts/ToastContext"; -import DatabaseProvider from "@/db/provider"; +import { DEFAULT_DATABASE_NAME, DrizzleDatabaseProvider } from "@/db/provider"; import { isBiometricsAuthEnabled, unlockWithBiometricsApp, @@ -25,9 +25,9 @@ export default function RootLayout() { }, [systemScheme]); return ( - + - + ); } diff --git a/src/db/provider.tsx b/src/db/provider.tsx index d1810cb1..204d0142 100644 --- a/src/db/provider.tsx +++ b/src/db/provider.tsx @@ -1,76 +1,188 @@ import Text from "@/components/Text"; import { drizzle } from "drizzle-orm/expo-sqlite"; import { useMigrations } from "drizzle-orm/expo-sqlite/migrator"; -import { openDatabaseSync, SQLiteProvider } from "expo-sqlite"; -import { Suspense, type PropsWithChildren } from "react"; +import { openDatabaseSync } from "expo-sqlite"; +import { + createContext, + Suspense, + useContext, + type PropsWithChildren, +} from "react"; import { View } from "react-native"; import { ActivityIndicator } from "react-native-paper"; import { SafeAreaView } from "react-native-safe-area-context"; + import migrations from "./drizzle/migrations"; +import * as schema from "./schema"; + +export const DEFAULT_DATABASE_NAME = "master.db"; + +type DrizzleDatabase = ReturnType; -export const DATABASE_NAME = "master.db"; +const DrizzleDatabaseContext = createContext( + undefined, +); -export default function DatabaseProvider({ children }: PropsWithChildren) { - const expoDb = openDatabaseSync(DATABASE_NAME); +export interface DrizzleDatabaseProviderProps extends PropsWithChildren { + /** + * Name of the SQLite database file. + */ + databaseName: string; +} + +/** + * Provides a single shared Drizzle database instance to the + * entire component tree. + * + * The provider owns the complete database lifecycle: + * + * 1. Opens the Expo SQLite database. + * 2. Creates the Drizzle database instance. + * 3. Runs Drizzle migrations. + * 4. Waits until migrations have completed successfully. + * 5. Provides the ready Drizzle database through React context. + * + * Children are never rendered before the database is ready. + * Migration failures are displayed using the provider's fatal + * database error UI. + * + * The database instance is shared by all descendants. Consumers + * should access it using `useDrizzleDatabase()` instead of opening + * their own SQLite connection. + * + * @example + * ```tsx + * + * + * + * ``` + */ +export function DrizzleDatabaseProvider({ + children, + databaseName, +}: DrizzleDatabaseProviderProps) { + const expoDb = openDatabaseSync(databaseName, { + enableChangeListener: true, + }); - const db = drizzle(expoDb); + const db = drizzle(expoDb, { schema }); const { success, error } = useMigrations(db, migrations); if (error) { - return ( - ; + } + + if (!success) { + return ; + } + + return ( + + }>{children} + + ); +} + +/** + * Returns the shared Drizzle database. + * + * this hook is only intended to be use inside `DrizzleDatabaseProvider`. + */ +export function useDrizzleDatabase(): DrizzleDatabase { + const db = useContext(DrizzleDatabaseContext); + + if (db === undefined) { + throw new Error( + "useDrizzleDatabase must be used inside DrizzleDatabaseProvider.", + ); + } + + return db; +} + +function DrizzleDatabaseLoading() { + return ( + + + + ); +} + +function DrizzleDatabaseError({ error }: { error: unknown }) { + return ( + + - - Something went wrong!! - - - Please close & reopen the app. + + ! - - ); - } - if (!success) { - return ( - - - - ); - } + + Database initialization failed + - return ( - - - - } - > - - {children} - - + Passcodes couldn't prepare its local database. Please close and reopen + the app. + + + ); } diff --git a/src/libs/withSQLiteDatabase.ts b/src/libs/withSQLiteDatabase.ts new file mode 100644 index 00000000..44bcbbea --- /dev/null +++ b/src/libs/withSQLiteDatabase.ts @@ -0,0 +1,28 @@ +import * as SQLite from "expo-sqlite"; + +/** + * Opens a SQLite database, passes the connection to the callback, + * returns the callback result, and closes the database afterward. + * + * The callback can return either a value or a Promise. + * + * @example + * ```ts + * const result = await withSQLiteDatabase( + * "master.db", + * (db) => query(db), + * ); + * ``` + */ +export async function withSQLiteDatabase( + databaseName: string, + callback: (db: SQLite.SQLiteDatabase) => T | Promise, +): Promise { + const db = await SQLite.openDatabaseAsync(databaseName); + + try { + return await callback(db); + } finally { + await db.closeAsync(); + } +} From 16b0e014ac6d96beaa2397849ea98122c1a57af8 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Sat, 12 Sep 2026 22:36:21 +0530 Subject: [PATCH 09/12] refactor: add common global config. Signed-off-by: Jeel Dobariya --- app.config.ts | 14 ++++---- package-lock.json | 2 +- src/app/(tabs)/(settings)/data-recovery.tsx | 5 ++- .../(settings)/get-back-passwords.android.tsx | 4 +-- src/app/(tabs)/(settings)/settings.tsx | 14 ++++---- src/app/_layout.tsx | 5 +-- src/config.ts | 33 +++++++++++++++++++ src/db/provider.tsx | 8 ++--- src/libs/constants.ts | 9 ----- src/libs/data_recovery_test_db_mess.ts | 7 ++-- 10 files changed, 61 insertions(+), 40 deletions(-) create mode 100644 src/config.ts delete mode 100644 src/libs/constants.ts diff --git a/app.config.ts b/app.config.ts index 80f52d5a..336550d1 100644 --- a/app.config.ts +++ b/app.config.ts @@ -2,7 +2,7 @@ import "tsx/cjs"; import { ConfigContext, ExpoConfig } from "expo/config"; -import constants from "@/libs/constants"; +import AppConfig from "@/config"; import buildPropertiesPlugin from "expo-build-properties/plugin"; import devBuildPlugin from "expo-dev-client/plugin"; import localAuthenticationPlugin from "expo-local-authentication/plugin"; @@ -70,9 +70,9 @@ if (!IS_PRODUCTION_BUILD) { export default ({ config }: ConfigContext): ExpoConfig => ({ ...config, - name: constants.appname + appNameSuffix, + name: AppConfig.APP_NAME + appNameSuffix, slug: "passcodes", - version: constants.build.version + versionNameSuffix, + version: AppConfig.BUILD_VERSION + versionNameSuffix, orientation: "default", icon: launcherAppIcon, @@ -82,8 +82,8 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ platforms: ["android", "ios"], ios: { - buildNumber: constants.build.versionCodeIos, - version: constants.build.version, + buildNumber: AppConfig.BUILD_IOS_VERSIONCODE, + version: AppConfig.BUILD_VERSION, icon: launcherAppIcon, bundleIdentifier: "com.jeeldobariya.passcodes.earlybeta" + packageNameSuffix, @@ -94,8 +94,8 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ }, android: { - versionCode: constants.build.versionCodeAndroid, - version: constants.build.version + versionNameSuffix, + versionCode: AppConfig.BUILD_ANDROID_VERSIONCODE, + version: AppConfig.BUILD_VERSION, package: "com.jeeldobariya.passcodes" + packageNameSuffix, icon: launcherAppIcon, adaptiveIcon: { diff --git a/package-lock.json b/package-lock.json index cb95000b..f0756023 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3348,7 +3348,7 @@ }, "node_modules/@passcodes/passalgo": { "version": "0.1.0", - "resolved": "git+ssh://git@github.com/PasscodesApp/PassAlgo.git#17e4baf73539584f4144e2feb83aa651bfb0504d", + "resolved": "git+ssh://git@github.com/PasscodesApp/PassAlgo.git#0b19e9c7324bc49fc189ba362588badf4c350546", "license": "MIT" }, "node_modules/@radix-ui/primitive": { diff --git a/src/app/(tabs)/(settings)/data-recovery.tsx b/src/app/(tabs)/(settings)/data-recovery.tsx index 72bb0e11..ace9688a 100644 --- a/src/app/(tabs)/(settings)/data-recovery.tsx +++ b/src/app/(tabs)/(settings)/data-recovery.tsx @@ -1,5 +1,6 @@ import ScreenHeading from "@/components/ScreenHeading"; import Text from "@/components/Text"; +import Config from "@/config"; import dataRecoveryFromTestDB from "@/libs/data_recovery_test_db_mess"; import { withSQLiteDatabase } from "@/libs/withSQLiteDatabase"; import { useEffect, useState } from "react"; @@ -10,8 +11,6 @@ type MigrationResult = { message: string; }; -const OLD_DATABASE_NAME = "test2.db"; - export default function DataRecoveryScreen() { const [result, setResult] = useState({ state: "Running", @@ -20,7 +19,7 @@ export default function DataRecoveryScreen() { useEffect(() => { async function runMigration() { - await withSQLiteDatabase(OLD_DATABASE_NAME, async (expoDb) => { + await withSQLiteDatabase(Config.DATABASE_NAME, async (expoDb) => { await dataRecoveryFromTestDB(expoDb); }); } diff --git a/src/app/(tabs)/(settings)/get-back-passwords.android.tsx b/src/app/(tabs)/(settings)/get-back-passwords.android.tsx index 48e8c0e7..cfd6fe4d 100644 --- a/src/app/(tabs)/(settings)/get-back-passwords.android.tsx +++ b/src/app/(tabs)/(settings)/get-back-passwords.android.tsx @@ -1,6 +1,6 @@ import ScreenHeading from "@/components/ScreenHeading"; import Text from "@/components/Text"; -import { DEFAULT_DATABASE_NAME } from "@/db/provider"; +import Config from "@/config"; import roomDrizzleMigration from "@/libs/room_drizzle_migration"; import { withSQLiteDatabase } from "@/libs/withSQLiteDatabase"; import AsyncStorage from "expo-sqlite/kv-store"; @@ -50,7 +50,7 @@ export default function GetBackPasswordsScreen() { // Run migration const result = await withSQLiteDatabase( - DEFAULT_DATABASE_NAME, + Config.DATABASE_NAME, async (expoDb) => { return await roomDrizzleMigration(expoDb); }, diff --git a/src/app/(tabs)/(settings)/settings.tsx b/src/app/(tabs)/(settings)/settings.tsx index 75f82b7f..05b4826d 100644 --- a/src/app/(tabs)/(settings)/settings.tsx +++ b/src/app/(tabs)/(settings)/settings.tsx @@ -1,13 +1,13 @@ import LinkButton from "@/components/LinkButton"; import { LinkIconButton } from "@/components/LinkIconButton"; import Text from "@/components/Text"; +import Config from "@/config"; import { passwords } from "@/db/schema"; import { isBiometricsAuthEnabled, toggleBiometricsFeature, unlockWithBiometricsApp, } from "@/libs/biometric"; -import constants from "@/libs/constants"; import { getGooglePasswordsCSVContent, type PasswordCSVFormat, @@ -303,10 +303,10 @@ export default function SettingsScreen() { ( ( ( ( + ); diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 00000000..9b799d07 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,33 @@ +export type SocialLinks = `https://${string}` | `mailto:${string}`; + +const config = { + // ---------------------- + // Main Config + // ---------------------- + APP_NAME: "Passcodes", + VERSION: "v4.0.0 - RC.1", + + // ---------------------- + // Build Config + // ---------------------- + BUILD_VERSION: "v4.0.0-RC.1", // same as VERSION, just without spaces. + BUILD_ANDROID_VERSIONCODE: 10, + BUILD_IOS_VERSIONCODE: "1.0.0", + + // ---------------------- + // Social Config + // ---------------------- + SOCIAL_EMAIL_US: "mailto:jeeldobariya38@gmail.com" as SocialLinks, + SOCIAL_GITHUB: "https://github.com/PasscodesApp/Passcodes" as SocialLinks, + SOCIAL_TELEGRAM: "https://t.me/passcodescommunity" as SocialLinks, + SOCIAL_DISCORD: "https://discord.gg/kSSkYq7KAQ" as SocialLinks, + + // ---------------------- + // Database Config + // ---------------------- + DATABASE_NAME: "master.db", + OLD_MISTAKEN_DATABASE_NAME: "test2.db", // This variable should never be editted in anycases... +}; + +export type AppConfig = typeof config; +export default config; diff --git a/src/db/provider.tsx b/src/db/provider.tsx index 204d0142..6956714c 100644 --- a/src/db/provider.tsx +++ b/src/db/provider.tsx @@ -15,15 +15,13 @@ import { SafeAreaView } from "react-native-safe-area-context"; import migrations from "./drizzle/migrations"; import * as schema from "./schema"; -export const DEFAULT_DATABASE_NAME = "master.db"; - -type DrizzleDatabase = ReturnType; +export type DrizzleDatabase = ReturnType; const DrizzleDatabaseContext = createContext( undefined, ); -export interface DrizzleDatabaseProviderProps extends PropsWithChildren { +interface DrizzleDatabaseProviderProps extends PropsWithChildren { /** * Name of the SQLite database file. */ @@ -59,7 +57,7 @@ export interface DrizzleDatabaseProviderProps extends PropsWithChildren { * * ``` */ -export function DrizzleDatabaseProvider({ +export default function DrizzleDatabaseProvider({ children, databaseName, }: DrizzleDatabaseProviderProps) { diff --git a/src/libs/constants.ts b/src/libs/constants.ts deleted file mode 100644 index 65ef859c..00000000 --- a/src/libs/constants.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default { - appname: "Passcodes", - version: "v4.0.0 - RC.1", - build: { - version: "v4.0.0-RC.1", - versionCodeAndroid: 10, - versionCodeIos: "1.0.0", - }, -}; diff --git a/src/libs/data_recovery_test_db_mess.ts b/src/libs/data_recovery_test_db_mess.ts index 0009e292..a6432de9 100644 --- a/src/libs/data_recovery_test_db_mess.ts +++ b/src/libs/data_recovery_test_db_mess.ts @@ -1,14 +1,13 @@ +import Config from "@/config"; import * as SQLite from "expo-sqlite"; -const OLD_DATABASE_NAME = "test2.db"; - export default async function dataRecoveryFromTestDB( expoDb: SQLite.SQLiteDatabase, ) { let oldDb: SQLite.SQLiteDatabase | undefined = undefined; try { - oldDb = await SQLite.openDatabaseAsync(OLD_DATABASE_NAME); + oldDb = await SQLite.openDatabaseAsync(Config.OLD_MISTAKEN_DATABASE_NAME); // Verify passwords table exists const tableExists = await oldDb.getFirstAsync( @@ -20,7 +19,7 @@ export default async function dataRecoveryFromTestDB( if (!tableExists) { await oldDb.closeAsync(); - await SQLite.deleteDatabaseAsync(OLD_DATABASE_NAME); + await SQLite.deleteDatabaseAsync(Config.OLD_MISTAKEN_DATABASE_NAME); return; } From d3cf53020b8febda50ff4b8e59929a7379629ebf Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Sun, 13 Sep 2026 14:53:58 +0530 Subject: [PATCH 10/12] build: improve typescript config Signed-off-by: Jeel Dobariya --- src/db/schema.ts | 13 +++++++++++++ tsconfig.json | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/src/db/schema.ts b/src/db/schema.ts index 7999cf4e..9d720fee 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -10,4 +10,17 @@ export const passwords = sqliteTable("passwords", { url: text("url"), createdAt: text("created_at").default(sql`(CURRENT_TIMESTAMP)`), updatedAt: text("updated_at").default(sql`(CURRENT_TIMESTAMP)`), + + /* + * Suggested Updates:- + * + * createdAt: text("created_at") + * .notNull() + * .default(sql`CURRENT_TIMESTAMP`), + * + * updatedAt: text("updated_at") + * .notNull() + * .default(sql`CURRENT_TIMESTAMP`) + * .$onUpdateFn(() => sql`CURRENT_TIMESTAMP`), + */ }); diff --git a/tsconfig.json b/tsconfig.json index b9cdd7ea..b96f4bd9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,15 @@ "extends": "expo/tsconfig.base", "compilerOptions": { "strict": true, + + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "forceConsistentCasingInFileNames": true, + "paths": { "@/*": ["./src/*"], "@plugins/*": ["./plugins/*"] From 0016c88ec4c58ee603dddb05ffdf0f145f194ecb Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Sun, 13 Sep 2026 15:19:01 +0530 Subject: [PATCH 11/12] refactor: add password repository Signed-off-by: Jeel Dobariya --- src/app/(tabs)/(password-manager)/index.tsx | 8 +- .../(password-manager)/password-details.tsx | 42 +++++----- .../(password-manager)/save-password.tsx | 56 +++++++------- src/app/(tabs)/(settings)/settings.tsx | 4 +- src/db/provider.tsx | 8 +- src/repositories/PasswordRepository.ts | 77 +++++++++++++++++++ 6 files changed, 137 insertions(+), 58 deletions(-) create mode 100644 src/repositories/PasswordRepository.ts diff --git a/src/app/(tabs)/(password-manager)/index.tsx b/src/app/(tabs)/(password-manager)/index.tsx index 51307e69..22ab0b14 100644 --- a/src/app/(tabs)/(password-manager)/index.tsx +++ b/src/app/(tabs)/(password-manager)/index.tsx @@ -1,10 +1,9 @@ import PasswordItemCard from "@/components/PasswordItemCard"; import Text from "@/components/Text"; import { useDrizzleDatabase } from "@/db/provider"; -import { passwords } from "@/db/schema"; +import { PasswordRepository } from "@/repositories/PasswordRepository"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; import { FlashList } from "@shopify/flash-list"; -import { eq } from "drizzle-orm"; import { useLiveQuery } from "drizzle-orm/expo-sqlite"; import { router, Stack } from "expo-router"; import { useMemo, useState } from "react"; @@ -22,9 +21,10 @@ export default function LoadPasswordScreen() { const theme = useTheme(); const db = useDrizzleDatabase(); + const passwordRepository = new PasswordRepository(db); const { data: passwordList = [] } = useLiveQuery( - db.select().from(passwords), + passwordRepository.observeAll(), [refreshKey], ); @@ -65,7 +65,7 @@ export default function LoadPasswordScreen() { { text: "Delete", onPress: async () => { - await db.delete(passwords).where(eq(passwords.id, password.id)); + await passwordRepository.delete(password.id); }, style: "destructive", }, diff --git a/src/app/(tabs)/(password-manager)/password-details.tsx b/src/app/(tabs)/(password-manager)/password-details.tsx index 97932c0e..13964a28 100644 --- a/src/app/(tabs)/(password-manager)/password-details.tsx +++ b/src/app/(tabs)/(password-manager)/password-details.tsx @@ -5,12 +5,11 @@ import PasswordFormCard, { import { useToast } from "@/contexts/ToastContext"; import { useDrizzleDatabase } from "@/db/provider"; -import { passwords } from "@/db/schema"; import { getScreenShotSecureScreen } from "@/libs/screenshot_prevention"; +import { PasswordRepository } from "@/repositories/PasswordRepository"; import { formatDate } from "@passcodes/passalgo"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; -import { eq } from "drizzle-orm"; import { Href, router, useLocalSearchParams } from "expo-router"; import { usePreventRemove } from "expo-router/react-navigation"; @@ -24,6 +23,7 @@ export default function PasswordDetailsScreen() { const { id } = useLocalSearchParams(); const db = useDrizzleDatabase(); + const passwordRepository = new PasswordRepository(db); const { state, setState, updateField } = usePasswordForm(); const [isEditing, setIsEditing] = useState(false); @@ -46,23 +46,24 @@ export default function PasswordDetailsScreen() { } async function loadAndRefreshPassword() { - const result = await db - .select() - .from(passwords) - .where(eq(passwords.id, Number(id))); - - if (result.length > 0) { - const data = result[0]; - - setState({ - domain: data.domain || "", - username: data.username || "", - password: data.password || "", - url: data.url || "", - notes: data.notes || "", - updatedAt: data.updatedAt ? formatDate(data.updatedAt) : "just now", - }); + const password = await passwordRepository.getById(Number(id)); + + if (!password) { + // Password doesn't exist + // TODO: redirect to error or go back(). + return; } + + setState({ + domain: password.domain, + username: password.username, + password: password.password, + url: password.url || "", + notes: password.notes || "", + updatedAt: password.updatedAt + ? formatDate(password.updatedAt) + : "just now", + }); } async function updatePassword() { @@ -75,10 +76,7 @@ export default function PasswordDetailsScreen() { unfocusAllFields(); try { - await db - .update(passwords) - .set({ ...state, updatedAt: new Date().toISOString() }) - .where(eq(passwords.id, Number(id))); + await passwordRepository.update(Number(id), state); setIsEditing(false); diff --git a/src/app/(tabs)/(password-manager)/save-password.tsx b/src/app/(tabs)/(password-manager)/save-password.tsx index f53ec0c5..61071b95 100644 --- a/src/app/(tabs)/(password-manager)/save-password.tsx +++ b/src/app/(tabs)/(password-manager)/save-password.tsx @@ -2,12 +2,12 @@ import FormTextField from "@/components/FormTextField"; import SecureTextField from "@/components/SecureTextField"; import { useToast } from "@/contexts/ToastContext"; import { useDrizzleDatabase } from "@/db/provider"; -import { passwords } from "@/db/schema"; import { getScreenShotSecureScreen } from "@/libs/screenshot_prevention"; +import { PasswordRepository } from "@/repositories/PasswordRepository"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; import { router } from "expo-router"; import { useState } from "react"; -import { Alert, ScrollView, View } from "react-native"; +import { ScrollView, View } from "react-native"; import { Button } from "react-native-paper"; import { SafeAreaView } from "react-native-safe-area-context"; @@ -19,6 +19,30 @@ export default function SavePasswordScreen() { let [notes, setNotes] = useState(""); const db = useDrizzleDatabase(); + const passwordRepository = new PasswordRepository(db); + + async function handleSavePassword() { + if (!domain || !username || !password) { + showToast("Domain, Username and Password are required.", "error"); + return; + } + + try { + await passwordRepository.create({ + domain, + username, + password, + notes, + url, + }); + + showToast("Password saved successfully"); + router.back(); + } catch (err) { + console.error(err); + showToast("Failed to save, please try again!!", "error"); + } + } const { showToast } = useToast(); @@ -93,33 +117,7 @@ export default function SavePasswordScreen() { iconStyle="solid" /> )} - onPress={() => { - if (!domain || !username || !password) { - Alert.alert( - "Missing Fields", - "Domain, Username and Password are required.", - ); - return; - } - - db.insert(passwords) - .values({ - domain, - username, - password, - notes, - url, - }) - .then(() => { - showToast("Password saved successfully"); - router.back(); - }) - .catch((err) => { - console.error(err); - showToast("Failed to save, please try again!!", "error"); - Alert.alert("Error", "Failed to save password."); - }); - }} + onPress={handleSavePassword} > Save Password diff --git a/src/app/(tabs)/(settings)/settings.tsx b/src/app/(tabs)/(settings)/settings.tsx index 05b4826d..0cc6fb42 100644 --- a/src/app/(tabs)/(settings)/settings.tsx +++ b/src/app/(tabs)/(settings)/settings.tsx @@ -29,6 +29,7 @@ import { Card, Divider, List, Switch, useTheme } from "react-native-paper"; import { SafeAreaView } from "react-native-safe-area-context"; import { useDrizzleDatabase } from "@/db/provider"; +import { PasswordRepository } from "@/repositories/PasswordRepository"; import PasscodesAutofillServiceModule from "../../../../modules/passcodes-autofill-service/src/PasscodesAutofillServiceModule"; export default function SettingsScreen() { @@ -50,6 +51,7 @@ export default function SettingsScreen() { const theme = useTheme(); let db = useDrizzleDatabase(); + const passwordRepository = new PasswordRepository(db); async function handleImportPasswords() { let content = await getCSVPasswordString(); @@ -72,7 +74,7 @@ export default function SettingsScreen() { } async function handleExportPasswords() { - const result: PasswordCSVFormat[] = await db.select().from(passwords); + const result: PasswordCSVFormat[] = await passwordRepository.getAll(); let content = await getGooglePasswordsCSVContent(result); sharePasswordAsCSV(content); diff --git a/src/db/provider.tsx b/src/db/provider.tsx index 6956714c..e423a6cd 100644 --- a/src/db/provider.tsx +++ b/src/db/provider.tsx @@ -108,9 +108,13 @@ function DrizzleDatabaseLoading() { flex: 1, alignItems: "center", justifyContent: "center", + backgroundColor: "#020221", }} > - + + + Please Wait..... + Opening Local Database... ); } @@ -122,6 +126,7 @@ function DrizzleDatabaseError({ error }: { error: unknown }) { flex: 1, alignItems: "center", justifyContent: "center", + backgroundColor: "#020221", paddingHorizontal: 24, }} > @@ -129,7 +134,6 @@ function DrizzleDatabaseError({ error }: { error: unknown }) { style={{ width: "100%", maxWidth: 420, - backgroundColor: "#020221", padding: 24, borderRadius: 24, alignItems: "center", diff --git a/src/repositories/PasswordRepository.ts b/src/repositories/PasswordRepository.ts new file mode 100644 index 00000000..3a4760db --- /dev/null +++ b/src/repositories/PasswordRepository.ts @@ -0,0 +1,77 @@ +import type { DrizzleDatabase } from "@/db/provider"; +import { passwords } from "@/db/schema"; +import { eq, sql } from "drizzle-orm"; + +export interface CreatePasswordInput { + domain: string; + username: string; + password: string; + notes?: string | null; + url?: string | null; +} + +export interface UpdatePasswordInput { + domain?: string; + username?: string; + password?: string; + notes?: string | null; + url?: string | null; +} + +export class PasswordRepository { + constructor(private readonly db: DrizzleDatabase) {} + + /** + * Creates a query for observing all passwords. + * + * This does not execute the query. Pass the returned query + * to a reactive consumer such as `useLiveQuery`. + */ + observeAll() { + return this.db.select().from(passwords); + } + + async getAll() { + return this.observeAll(); + } + + async getById(id: number) { + const [password] = await this.db + .select() + .from(passwords) + .where(eq(passwords.id, id)); + + return password; + } + + async create(data: CreatePasswordInput) { + const [createdPassword] = await this.db + .insert(passwords) + .values(data) + .returning(); + + return createdPassword; + } + + async update(id: number, data: UpdatePasswordInput) { + const [updatedPassword] = await this.db + .update(passwords) + .set({ + ...data, + updatedAt: sql`CURRENT_TIMESTAMP`, // TODO: It will no longer be required, once drizzle `$onUpdate()` will be used. + }) + .where(eq(passwords.id, id)) + .returning(); + + return updatedPassword; + } + + async delete(id: number) { + const [deletedPassword] = await this.db + .delete(passwords) + .where(eq(passwords.id, id)) + .returning(); + + return deletedPassword; + } +} From 6f373839726c4158e06b6a6ed7b4862fb47e19fc Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Sun, 13 Sep 2026 16:23:17 +0530 Subject: [PATCH 12/12] refactor: add repository provider Signed-off-by: Jeel Dobariya --- src/app/(tabs)/(password-manager)/index.tsx | 6 +-- .../(password-manager)/password-details.tsx | 6 +-- .../(password-manager)/save-password.tsx | 6 +-- src/app/(tabs)/(settings)/settings.tsx | 27 ++-------- src/app/_layout.tsx | 6 +-- src/contexts/RepositoryContext.tsx | 54 +++++++++++++++++++ src/libs/importing.ts | 4 +- src/repositories/PasswordRepository.ts | 17 ++++++ 8 files changed, 88 insertions(+), 38 deletions(-) create mode 100644 src/contexts/RepositoryContext.tsx diff --git a/src/app/(tabs)/(password-manager)/index.tsx b/src/app/(tabs)/(password-manager)/index.tsx index 22ab0b14..a6f28a35 100644 --- a/src/app/(tabs)/(password-manager)/index.tsx +++ b/src/app/(tabs)/(password-manager)/index.tsx @@ -1,7 +1,6 @@ import PasswordItemCard from "@/components/PasswordItemCard"; import Text from "@/components/Text"; -import { useDrizzleDatabase } from "@/db/provider"; -import { PasswordRepository } from "@/repositories/PasswordRepository"; +import { usePasswordRepository } from "@/contexts/RepositoryContext"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; import { FlashList } from "@shopify/flash-list"; import { useLiveQuery } from "drizzle-orm/expo-sqlite"; @@ -20,8 +19,7 @@ export default function LoadPasswordScreen() { const theme = useTheme(); - const db = useDrizzleDatabase(); - const passwordRepository = new PasswordRepository(db); + const passwordRepository = usePasswordRepository(); const { data: passwordList = [] } = useLiveQuery( passwordRepository.observeAll(), diff --git a/src/app/(tabs)/(password-manager)/password-details.tsx b/src/app/(tabs)/(password-manager)/password-details.tsx index 13964a28..8412c0f7 100644 --- a/src/app/(tabs)/(password-manager)/password-details.tsx +++ b/src/app/(tabs)/(password-manager)/password-details.tsx @@ -2,11 +2,10 @@ import PasswordDetailCardActions from "@/components/PasswordDetailCardActions"; import PasswordFormCard, { usePasswordForm, } from "@/components/PasswordFormCard"; +import { usePasswordRepository } from "@/contexts/RepositoryContext"; import { useToast } from "@/contexts/ToastContext"; -import { useDrizzleDatabase } from "@/db/provider"; import { getScreenShotSecureScreen } from "@/libs/screenshot_prevention"; -import { PasswordRepository } from "@/repositories/PasswordRepository"; import { formatDate } from "@passcodes/passalgo"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; @@ -22,8 +21,7 @@ import { SafeAreaView } from "react-native-safe-area-context"; export default function PasswordDetailsScreen() { const { id } = useLocalSearchParams(); - const db = useDrizzleDatabase(); - const passwordRepository = new PasswordRepository(db); + const passwordRepository = usePasswordRepository(); const { state, setState, updateField } = usePasswordForm(); const [isEditing, setIsEditing] = useState(false); diff --git a/src/app/(tabs)/(password-manager)/save-password.tsx b/src/app/(tabs)/(password-manager)/save-password.tsx index 61071b95..e337fbde 100644 --- a/src/app/(tabs)/(password-manager)/save-password.tsx +++ b/src/app/(tabs)/(password-manager)/save-password.tsx @@ -1,9 +1,8 @@ import FormTextField from "@/components/FormTextField"; import SecureTextField from "@/components/SecureTextField"; +import { usePasswordRepository } from "@/contexts/RepositoryContext"; import { useToast } from "@/contexts/ToastContext"; -import { useDrizzleDatabase } from "@/db/provider"; import { getScreenShotSecureScreen } from "@/libs/screenshot_prevention"; -import { PasswordRepository } from "@/repositories/PasswordRepository"; import FontAwesome6 from "@react-native-vector-icons/fontawesome6"; import { router } from "expo-router"; import { useState } from "react"; @@ -18,8 +17,7 @@ export default function SavePasswordScreen() { let [url, setUrl] = useState(""); let [notes, setNotes] = useState(""); - const db = useDrizzleDatabase(); - const passwordRepository = new PasswordRepository(db); + const passwordRepository = usePasswordRepository(); async function handleSavePassword() { if (!domain || !username || !password) { diff --git a/src/app/(tabs)/(settings)/settings.tsx b/src/app/(tabs)/(settings)/settings.tsx index 0cc6fb42..1053c637 100644 --- a/src/app/(tabs)/(settings)/settings.tsx +++ b/src/app/(tabs)/(settings)/settings.tsx @@ -2,7 +2,6 @@ import LinkButton from "@/components/LinkButton"; import { LinkIconButton } from "@/components/LinkIconButton"; import Text from "@/components/Text"; import Config from "@/config"; -import { passwords } from "@/db/schema"; import { isBiometricsAuthEnabled, toggleBiometricsFeature, @@ -28,8 +27,7 @@ import { Alert, ScrollView } from "react-native"; import { Card, Divider, List, Switch, useTheme } from "react-native-paper"; import { SafeAreaView } from "react-native-safe-area-context"; -import { useDrizzleDatabase } from "@/db/provider"; -import { PasswordRepository } from "@/repositories/PasswordRepository"; +import { usePasswordRepository } from "@/contexts/RepositoryContext"; import PasscodesAutofillServiceModule from "../../../../modules/passcodes-autofill-service/src/PasscodesAutofillServiceModule"; export default function SettingsScreen() { @@ -45,32 +43,17 @@ export default function SettingsScreen() { const toggleScreenshotPreventSwitch = () => setIsScreenshotPreventEnabled(toggleScreenshotPreventionFeature()); - const [isAutofillEnabled, setIsAutofillEnabled] = useState( - PasscodesAutofillServiceModule.isAutofillServiceEnabled(), - ); + const isAutofillEnabled = + PasscodesAutofillServiceModule.isAutofillServiceEnabled(); const theme = useTheme(); - let db = useDrizzleDatabase(); - const passwordRepository = new PasswordRepository(db); + const passwordRepository = usePasswordRepository(); async function handleImportPasswords() { let content = await getCSVPasswordString(); let importPasswordList: PasswordCSVFormat[] = convertRawCSVToPasswords(content); - - db.transaction((tx) => { - importPasswordList.forEach((importablePassword) => { - tx.insert(passwords) - .values({ - domain: importablePassword.domain, - username: importablePassword.username, - password: importablePassword.password, - notes: importablePassword.notes, - url: importablePassword.url, - }) - .execute(); - }); - }); + await passwordRepository.importAll(importPasswordList); } async function handleExportPasswords() { diff --git a/src/app/_layout.tsx b/src/app/_layout.tsx index 143ebff0..db10e0da 100644 --- a/src/app/_layout.tsx +++ b/src/app/_layout.tsx @@ -1,7 +1,7 @@ import ScreenHeading from "@/components/ScreenHeading"; import Config from "@/config"; +import { RepositoryProvider } from "@/contexts/RepositoryContext"; import { ToastProvider } from "@/contexts/ToastContext"; -import DrizzleDatabaseProvider from "@/db/provider"; import { isBiometricsAuthEnabled, unlockWithBiometricsApp, @@ -26,9 +26,9 @@ export default function RootLayout() { }, [systemScheme]); return ( - + - + ); } diff --git a/src/contexts/RepositoryContext.tsx b/src/contexts/RepositoryContext.tsx new file mode 100644 index 00000000..a79c6e3b --- /dev/null +++ b/src/contexts/RepositoryContext.tsx @@ -0,0 +1,54 @@ +import { createContext, PropsWithChildren, useContext, useMemo } from "react"; + +import DrizzleDatabaseProvider, { useDrizzleDatabase } from "@/db/provider"; +import { PasswordRepository } from "@/repositories/PasswordRepository"; + +type Repositories = { + password: PasswordRepository; +}; + +const RepositoryContext = createContext(undefined); + +function RepositoryProviderContent({ + children, +}: { + children: React.ReactNode; +}) { + const db = useDrizzleDatabase(); + + const repositories = useMemo( + () => ({ + password: new PasswordRepository(db), + }), + [db], + ); + + return ( + + {children} + + ); +} + +export function RepositoryProvider({ + dbName, + children, +}: PropsWithChildren<{ dbName: string }>) { + return ( + + {children} + + ); +} + +export function usePasswordRepository(): PasswordRepository { + const repositories = useContext(RepositoryContext); + + if (!repositories) { + throw new Error( + "usePasswordRepository must be used inside RepositoryProvider", + ); + } + + return repositories.password; +} diff --git a/src/libs/importing.ts b/src/libs/importing.ts index 60a1bd40..81cf8da9 100644 --- a/src/libs/importing.ts +++ b/src/libs/importing.ts @@ -29,7 +29,9 @@ export function convertRawCSVToPasswords( lines.shift(); return lines.map((line) => { - const [domain, url, username, password, notes = ""] = line.split(","); + // TODO: Assigning empty string is tempoary solution, we will improve this later. + const [domain = "", url = "", username = "", password = "", notes = ""] = + line.split(","); return { domain: domain, diff --git a/src/repositories/PasswordRepository.ts b/src/repositories/PasswordRepository.ts index 3a4760db..ea43a861 100644 --- a/src/repositories/PasswordRepository.ts +++ b/src/repositories/PasswordRepository.ts @@ -53,6 +53,23 @@ export class PasswordRepository { return createdPassword; } + // TODO: temporary solution we will create a upsert all method + async importAll(data: CreatePasswordInput[]) { + this.db.transaction((tx) => { + data.forEach((importablePassword) => { + tx.insert(passwords) + .values({ + domain: importablePassword.domain, + username: importablePassword.username, + password: importablePassword.password, + notes: importablePassword.notes, + url: importablePassword.url, + }) + .execute(); + }); + }); + } + async update(id: number, data: UpdatePasswordInput) { const [updatedPassword] = await this.db .update(passwords)