diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dbff946
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+node_modules/
+.expo/
+dist/
+npm-debug.*
+*.jks
+*.p8
+*.p12
+*.key
+*.mobileprovision
+*.orig.*
+web-build/
+.expo-export-check/
+.expo-export-ios/
+.DS_Store
+*.log
+.env
+.env.local
+
+# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
+# The following patterns were generated by expo-cli
+
+expo-env.d.ts
+# @end expo-cli
\ No newline at end of file
diff --git a/README.md b/README.md
index e69de29..70191db 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,31 @@
+# Gishen Pharmacy — Mobile
+
+React Native (Expo) customer app for Gishen Pharmacy.
+
+## Stack
+
+- Expo SDK 53 + expo-router
+- NativeWind / Tailwind
+- Zustand + AsyncStorage
+- i18next (`en` / `am`)
+
+## Run
+
+```bash
+npm install --legacy-peer-deps
+npx expo start
+```
+
+## Brand
+
+Colors and logo from Gishen-Ecom (`#A8C73A` / `#141414`).
+
+## Backend
+
+Living contract: [`docs/BACKEND_SPEC.md`](docs/BACKEND_SPEC.md) — update whenever features change.
+
+## Demo
+
+- OTP: any 4+ digits (hint `1234`)
+- Org join codes: `GISHEN-BANK`, `GISHEN-NGO`
+- Payments: Chapa / Telebirr / M-Pesa; pay-at-branch only for pickup
diff --git a/app.json b/app.json
new file mode 100644
index 0000000..c239ca7
--- /dev/null
+++ b/app.json
@@ -0,0 +1,73 @@
+{
+ "expo": {
+ "name": "Gishen Pharmacy",
+ "slug": "gishen-mob",
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "scheme": "gishen",
+ "userInterfaceStyle": "light",
+ "newArchEnabled": true,
+ "splash": {
+ "image": "./assets/splash-icon.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#F6F7F2"
+ },
+ "ios": {
+ "supportsTablet": true,
+ "bundleIdentifier": "com.gishen.pharmacy",
+ "infoPlist": {
+ "NSCameraUsageDescription": "Gishen needs camera access to scan prescriptions.",
+ "NSPhotoLibraryUsageDescription": "Gishen needs photo access to upload prescriptions.",
+ "NSLocationWhenInUseUsageDescription": "Gishen uses your location to find the nearest branch.",
+ "NSFaceIDUsageDescription": "Gishen uses biometrics to unlock the app securely.",
+ "ITSAppUsesNonExemptEncryption": false
+ }
+ },
+ "android": {
+ "adaptiveIcon": {
+ "foregroundImage": "./assets/adaptive-icon.png",
+ "backgroundColor": "#F6F7F2"
+ },
+ "package": "com.gishen.pharmacy",
+ "permissions": [
+ "CAMERA",
+ "ACCESS_FINE_LOCATION",
+ "RECEIVE_BOOT_COMPLETED",
+ "VIBRATE"
+ ]
+ },
+ "plugins": [
+ "expo-router",
+ "expo-font",
+ [
+ "expo-camera",
+ {
+ "cameraPermission": "Allow Gishen to scan prescriptions."
+ }
+ ],
+ [
+ "expo-location",
+ {
+ "locationWhenInUsePermission": "Allow Gishen to find nearby branches."
+ }
+ ],
+ [
+ "expo-notifications",
+ {
+ "icon": "./assets/icon.png",
+ "color": "#A8C73A"
+ }
+ ],
+ "expo-local-authentication"
+ ],
+ "experiments": {
+ "typedRoutes": true
+ },
+ "extra": {
+ "router": {
+ "origin": false
+ }
+ }
+ }
+}
diff --git a/app/(root)/(screens)/_layout.tsx b/app/(root)/(screens)/_layout.tsx
new file mode 100644
index 0000000..4773c55
--- /dev/null
+++ b/app/(root)/(screens)/_layout.tsx
@@ -0,0 +1,13 @@
+import { Stack } from "expo-router";
+import { colors } from "@/lib/theme";
+
+export default function ScreensLayout() {
+ return (
+
+ );
+}
diff --git a/app/(root)/(screens)/about.tsx b/app/(root)/(screens)/about.tsx
new file mode 100644
index 0000000..a1c7c75
--- /dev/null
+++ b/app/(root)/(screens)/about.tsx
@@ -0,0 +1,96 @@
+import { Image, Linking, ScrollView, View } from "react-native";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card, InfoRow } from "@/components/ui/Card";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { brand } from "@/lib/data/brand";
+import { colors, gutter } from "@/lib/theme";
+
+export default function AboutScreen() {
+ return (
+
+
+
+
+
+
+
+ {brand.name}
+
+ Est. {brand.founded} · {brand.branchCount} branches
+
+
+
+
+
+
+
+
+
+
+
+ Our story
+
+ {brand.story}
+
+
+
+
+ Purpose
+
+ {brand.purpose}
+
+
+
+
+ Vision
+
+ {brand.vision}
+
+
+
+
+ Mission
+
+ {brand.mission}
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/(root)/(screens)/addresses.tsx b/app/(root)/(screens)/addresses.tsx
new file mode 100644
index 0000000..ccffe3c
--- /dev/null
+++ b/app/(root)/(screens)/addresses.tsx
@@ -0,0 +1,136 @@
+import { router } from "expo-router";
+import { useState } from "react";
+import { Alert, ScrollView, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { Field } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { useAddressStore } from "@/lib/stores/addressStore";
+import { useLocationStore } from "@/lib/stores/locationStore";
+import { colors, gutter } from "@/lib/theme";
+
+export default function AddressesScreen() {
+ const { t } = useTranslation();
+ const addresses = useAddressStore((s) => s.addresses);
+ const add = useAddressStore((s) => s.add);
+ const remove = useAddressStore((s) => s.remove);
+ const setDefault = useAddressStore((s) => s.setDefault);
+ const setAreaLabel = useLocationStore((s) => s.setAreaLabel);
+
+ const [label, setLabel] = useState("Home");
+ const [area, setArea] = useState("Bole, Addis Ababa");
+ const [street, setStreet] = useState("");
+ const [landmark, setLandmark] = useState("");
+ const [showForm, setShowForm] = useState(false);
+
+ return (
+
+
+
+ {addresses.map((a) => (
+
+
+
+ {a.label}
+
+ {a.street}
+
+
+ {a.area}
+ {a.landmark ? ` · ${a.landmark}` : ""}
+
+
+ {a.isDefault ? : null}
+
+
+ {!a.isDefault ? (
+ {
+ setDefault(a.id);
+ setAreaLabel(a.area);
+ }}
+ />
+ ) : (
+ {
+ setAreaLabel(a.area);
+ router.push("/(root)/(tabs)/cart");
+ }}
+ />
+ )}
+
+ Alert.alert("Remove address?", a.label, [
+ { text: "Cancel", style: "cancel" },
+ { text: "Remove", style: "destructive", onPress: () => remove(a.id) },
+ ])
+ }
+ />
+
+
+ ))}
+
+ {!showForm ? (
+ setShowForm(true)} />
+ ) : (
+
+
+ New address
+
+
+
+
+
+
+ {
+ if (!street.trim() || !area.trim()) {
+ Alert.alert("Missing info", "Area and street are required.");
+ return;
+ }
+ add({
+ label: label.trim() || "Address",
+ area: area.trim(),
+ street: street.trim(),
+ landmark: landmark.trim() || undefined,
+ isDefault: addresses.length === 0,
+ });
+ setStreet("");
+ setLandmark("");
+ setShowForm(false);
+ }}
+ />
+ setShowForm(false)} />
+
+
+ )}
+
+
+ );
+}
diff --git a/app/(root)/(screens)/branches.tsx b/app/(root)/(screens)/branches.tsx
new file mode 100644
index 0000000..676fd2e
--- /dev/null
+++ b/app/(root)/(screens)/branches.tsx
@@ -0,0 +1,146 @@
+import * as Location from "expo-location";
+import { router } from "expo-router";
+import { useMemo, useState } from "react";
+import { Alert, Linking, ScrollView, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { branches } from "@/lib/data/branches";
+import { routes } from "@/lib/routes";
+import { useLocationStore } from "@/lib/stores/locationStore";
+import { colors, gutter } from "@/lib/theme";
+
+function dist(a: { lat: number; lng: number }, b: { lat: number; lng: number }) {
+ const toRad = (d: number) => (d * Math.PI) / 180;
+ const R = 6371;
+ const dLat = toRad(b.lat - a.lat);
+ const dLng = toRad(b.lng - a.lng);
+ const x =
+ Math.sin(dLat / 2) ** 2 +
+ Math.cos(toRad(a.lat)) * Math.cos(toRad(b.lat)) * Math.sin(dLng / 2) ** 2;
+ return 2 * R * Math.asin(Math.sqrt(x));
+}
+
+export default function BranchesScreen() {
+ const { t } = useTranslation();
+ const setBranchId = useLocationStore((s) => s.setBranchId);
+ const setFulfillment = useLocationStore((s) => s.setFulfillment);
+ const setCoords = useLocationStore((s) => s.setCoords);
+ const branchId = useLocationStore((s) => s.branchId);
+ const [coords, setLocal] = useState<{ lat: number; lng: number } | null>(null);
+
+ const sorted = useMemo(() => {
+ if (!coords) return branches;
+ return [...branches].sort((a, b) => dist(coords, a) - dist(coords, b));
+ }, [coords]);
+
+ const useMyLocation = async () => {
+ const { status } = await Location.requestForegroundPermissionsAsync();
+ if (status !== "granted") {
+ Alert.alert("Location", "Permission denied");
+ return;
+ }
+ const pos = await Location.getCurrentPositionAsync({});
+ const c = { lat: pos.coords.latitude, lng: pos.coords.longitude };
+ setLocal(c);
+ setCoords(c.lat, c.lng);
+ };
+
+ return (
+
+
+
+
+ {t("common.nearestBranch")}
+
+ {sorted.map((b, index) => {
+ const selected = branchId === b.id;
+ const km = coords ? dist(coords, b) : null;
+ return (
+
+
+
+ {b.name}
+
+ {b.area}
+
+
+ {b.hours}
+ {b.pickupAvailable ? " · Pickup" : ""}
+
+
+
+ {selected ? : null}
+ {index === 0 && coords ? : null}
+ {km != null ? (
+
+ {km.toFixed(1)} km
+
+ ) : null}
+
+
+
+
+ Linking.openURL(`tel:${b.phone}`)}
+ />
+ Linking.openURL(b.mapsUrl)}
+ />
+ {
+ setBranchId(b.id);
+ setFulfillment("pickup");
+ Alert.alert("Pickup set", `${b.name} selected for checkout.`);
+ }}
+ />
+
+
+ );
+ })}
+
+ router.push(routes.checkout)}
+ />
+
+
+ );
+}
diff --git a/app/(root)/(screens)/checkout.tsx b/app/(root)/(screens)/checkout.tsx
new file mode 100644
index 0000000..746ceb9
--- /dev/null
+++ b/app/(root)/(screens)/checkout.tsx
@@ -0,0 +1,445 @@
+import { router } from "expo-router";
+import { useMemo, useState } from "react";
+import { Alert, Linking, Pressable, ScrollView, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Button } from "@/components/ui/Button";
+import { Card, InfoRow } from "@/components/ui/Card";
+import { Chip, Segmented } from "@/components/ui/Chip";
+import { Field, OptionRow } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { StickyBar } from "@/components/ui/StickyBar";
+import { Text } from "@/components/ui/Text";
+import { DELIVERY_FEE, orderSubtotalTotal, voucherDiscount } from "@/lib/commerce";
+import { branches } from "@/lib/data/branches";
+import { routes } from "@/lib/routes";
+import { useAddressStore } from "@/lib/stores/addressStore";
+import { useAuthStore } from "@/lib/stores/authStore";
+import { useCartStore } from "@/lib/stores/cartStore";
+import { useFamilyStore } from "@/lib/stores/familyStore";
+import { useLocationStore, type PaymentMethod } from "@/lib/stores/locationStore";
+import { useOrdersStore } from "@/lib/stores/ordersStore";
+import { useProfileModeStore } from "@/lib/stores/profileModeStore";
+import { colors, gutter } from "@/lib/theme";
+import { formatETB, WHATSAPP_NUMBER } from "@/lib/utils";
+
+export default function CheckoutScreen() {
+ const { t } = useTranslation();
+ const items = useCartStore((s) => s.items);
+ const clear = useCartStore((s) => s.clear);
+ const subtotal = useCartStore((s) => s.subtotal());
+ const cartVoucher = useCartStore((s) => s.voucherCode);
+ const setCartVoucher = useCartStore((s) => s.setVoucher);
+ const fulfillment = useLocationStore((s) => s.fulfillment);
+ const setFulfillment = useLocationStore((s) => s.setFulfillment);
+ const branchId = useLocationStore((s) => s.branchId);
+ const setBranchId = useLocationStore((s) => s.setBranchId);
+ const areaLabel = useLocationStore((s) => s.areaLabel);
+ const setAreaLabel = useLocationStore((s) => s.setAreaLabel);
+ const payment = useLocationStore((s) => s.paymentPreference);
+ const setPayment = useLocationStore((s) => s.setPaymentPreference);
+ const allowed = useLocationStore((s) => s.allowedPayments());
+ const addresses = useAddressStore((s) => s.addresses);
+ const defaultAddress = useAddressStore((s) => s.defaultAddress());
+ const addOrder = useOrdersStore((s) => s.addOrder);
+ const addPoints = useAuthStore((s) => s.addPoints);
+ const user = useAuthStore((s) => s.user);
+ const setActiveVoucher = useAuthStore((s) => s.setActiveVoucher);
+ const quoteSplit = useProfileModeStore((s) => s.quoteSplit);
+ const consumeAllowance = useProfileModeStore((s) => s.consumeAllowance);
+ const mode = useProfileModeStore((s) => s.mode);
+ const membership = useProfileModeStore((s) => s.activeMembership());
+ const familyMembers = useFamilyStore((s) => s.members);
+ const activeMemberId = useFamilyStore((s) => s.activeMemberId);
+ const setActiveMember = useFamilyStore((s) => s.setActiveMember);
+
+ const [name, setName] = useState(user?.name ?? "");
+ const [phone, setPhone] = useState(user?.phone ?? "");
+ const [notes, setNotes] = useState("");
+ const [addressId, setAddressId] = useState(defaultAddress?.id ?? "");
+ const [voucher, setVoucher] = useState(
+ cartVoucher || user?.activeVoucher || ""
+ );
+ const [forMemberId, setForMemberId] = useState(activeMemberId);
+
+ const selectedAddress = useMemo(
+ () => addresses.find((a) => a.id === addressId) ?? defaultAddress,
+ [addresses, addressId, defaultAddress]
+ );
+
+ const deliveryFee = fulfillment === "delivery" && items.length ? DELIVERY_FEE : 0;
+ const discount = voucherDiscount(subtotal, voucher);
+ const afterDiscount = Math.max(0, subtotal - discount);
+ const split =
+ mode === "corporate"
+ ? quoteSplit(afterDiscount)
+ : { covered: 0, selfPay: afterDiscount };
+ const total = orderSubtotalTotal({
+ subtotal: split.selfPay,
+ deliveryFee,
+ discount: 0,
+ });
+
+ const pay = () => {
+ if (!items.length) return;
+ if (!name.trim() || phone.trim().length < 9) {
+ Alert.alert("Contact details", "Enter your name and a valid phone number.");
+ return;
+ }
+ if (!allowed.includes(payment)) {
+ Alert.alert("Payment", "Select a valid payment method.");
+ return;
+ }
+ if (fulfillment === "pickup" && !branchId) {
+ Alert.alert("Pickup", "Select a branch for pickup.");
+ return;
+ }
+ if (fulfillment === "delivery" && !selectedAddress && !areaLabel.trim()) {
+ Alert.alert("Delivery", "Choose a saved address or enter an area.");
+ return;
+ }
+
+ const branch = branches.find((b) => b.id === branchId);
+ const addressLine = selectedAddress
+ ? `${selectedAddress.street}${selectedAddress.landmark ? ` · ${selectedAddress.landmark}` : ""}`
+ : undefined;
+
+ const forMember = familyMembers.find((m) => m.id === forMemberId);
+ const orderNotes = [
+ notes.trim(),
+ forMember ? `For family: ${forMember.name} (${forMember.relationship})` : "",
+ ]
+ .filter(Boolean)
+ .join(" · ");
+
+ const order = addOrder({
+ items,
+ subtotal,
+ deliveryFee,
+ discount,
+ voucherCode: discount ? voucher.trim().toUpperCase() : null,
+ total: afterDiscount + deliveryFee,
+ fulfillment,
+ branchId,
+ areaLabel:
+ fulfillment === "pickup"
+ ? branch?.area ?? areaLabel
+ : selectedAddress?.area ?? areaLabel,
+ addressId: fulfillment === "delivery" ? selectedAddress?.id ?? null : null,
+ addressLine,
+ paymentMethod: payment,
+ corporateCovered: split.covered,
+ selfPay: split.selfPay + deliveryFee,
+ customerName: name.trim(),
+ customerPhone: phone.trim(),
+ notes: orderNotes,
+ riderAssigned: false,
+ });
+
+ if (forMemberId) setActiveMember(forMemberId);
+
+ if (split.covered > 0) consumeAllowance(split.covered);
+ addPoints(Math.max(1, Math.floor(afterDiscount / 10)), "Order reward");
+ if (discount) {
+ setActiveVoucher(null);
+ setCartVoucher(null);
+ }
+ clear();
+
+ Alert.alert(
+ "Order placed",
+ payment === "pay_at_branch"
+ ? `Pay ${formatETB(order.selfPay ?? order.total)} at ${branch?.name ?? "the branch"}.`
+ : `Mock ${labelPayment(payment, t)} payment of ${formatETB(order.total)} succeeded.`,
+ [
+ { text: "View order", onPress: () => router.replace(routes.orderDetail(order.id)) },
+ { text: "Track", onPress: () => router.replace(routes.tracking(order.id)) },
+ ]
+ );
+ };
+
+ const whatsapp = () => {
+ const lines = items
+ .map((i) => `• ${i.name} x${i.quantity} — ${i.price * i.quantity} ETB`)
+ .join("%0A");
+ const msg = `Gishen order%0AName: ${name}%0APhone: ${phone}%0A${lines}%0ATotal: ${total} ETB%0A${fulfillment}%0A${notes}`;
+ Linking.openURL(`https://wa.me/${WHATSAPP_NUMBER}?text=${msg}`);
+ };
+
+ if (!items.length) {
+ return (
+
+
+
+
+ Your cart is empty. Add products before checking out.
+
+ router.replace(routes.shop)}
+ />
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ Contact
+
+ {familyMembers.length ? (
+
+
+ Ordering for
+
+
+ setForMemberId(null)}
+ size="sm"
+ />
+ {familyMembers.map((m) => (
+ setForMemberId(m.id)}
+ size="sm"
+ />
+ ))}
+
+
+ ) : null}
+
+
+
+
+
+
+
+
+
+ Fulfillment
+
+
+
+ {fulfillment === "delivery" ? (
+
+
+
+ Saved addresses
+
+ router.push(routes.addresses)}>
+
+ Manage
+
+
+
+ {addresses.map((a) => (
+ {
+ setAddressId(a.id);
+ setAreaLabel(a.area);
+ }}
+ style={{
+ padding: 12,
+ borderRadius: 14,
+ borderWidth: 1.5,
+ borderColor: addressId === a.id ? colors.brand : colors.line,
+ backgroundColor: addressId === a.id ? colors.brandWash : colors.surface,
+ }}
+ >
+
+ {a.label}
+ {a.isDefault ? " · Default" : ""}
+
+
+ {a.street}
+
+
+ {a.area}
+
+
+ ))}
+
+
+ ) : (
+
+ {branches.map((b) => (
+ setBranchId(b.id)}
+ style={{
+ padding: 12,
+ borderRadius: 14,
+ borderWidth: 1.5,
+ borderColor: branchId === b.id ? colors.brand : colors.line,
+ backgroundColor: branchId === b.id ? colors.brandWash : colors.surface,
+ }}
+ >
+ {b.name}
+
+ {b.area} · {b.hours}
+
+
+ ))}
+
+ )}
+
+
+
+
+ {t("common.payment")}
+ {fulfillment === "delivery" ? (
+
+ Pay at branch is only available for pickup
+
+ ) : null}
+
+ {allowed.map((m, i) => (
+ setPayment(m)}
+ icon={paymentIcon(m)}
+ last={i === allowed.length - 1}
+ />
+ ))}
+
+
+
+
+ Voucher
+
+
+
+ setVoucher("GISHEN10")} selected={voucher.toUpperCase() === "GISHEN10"} />
+ {user?.activeVoucher ? (
+ setVoucher(user.activeVoucher!)}
+ selected={voucher === user.activeVoucher}
+ />
+ ) : null}
+
+
+
+ {mode === "corporate" && membership ? (
+
+ Corporate split · {membership.orgName}
+
+ Plan {membership.planName} · {formatETB(membership.remainingAllowance)} left this month
+
+
+ Covered: {formatETB(split.covered)}
+
+ You pay: {formatETB(split.selfPay + deliveryFee)}
+
+ ) : null}
+
+
+
+
+ {discount > 0 ? (
+
+ ) : null}
+
+
+
+
+
+
+
+
+
+
+
+ Total due
+
+ {formatETB(afterDiscount + deliveryFee)}
+
+
+
+
+
+ );
+}
+
+function labelPayment(m: PaymentMethod, t: (k: string) => string) {
+ if (m === "chapa") return t("common.chapa");
+ if (m === "telebirr") return t("common.telebirr");
+ if (m === "mpesa") return t("common.mpesa");
+ return t("common.payAtBranch");
+}
+
+function paymentHint(m: PaymentMethod) {
+ if (m === "chapa") return "Card / mobile money via Chapa";
+ if (m === "telebirr") return "Ethio telecom Telebirr";
+ if (m === "mpesa") return "Safaricom M-Pesa";
+ return "Cash or POS when you collect";
+}
+
+function paymentIcon(m: PaymentMethod): keyof typeof import("@expo/vector-icons").Ionicons.glyphMap {
+ if (m === "pay_at_branch") return "storefront-outline";
+ if (m === "telebirr") return "phone-portrait-outline";
+ if (m === "mpesa") return "cash-outline";
+ return "card-outline";
+}
diff --git a/app/(root)/(screens)/contact.tsx b/app/(root)/(screens)/contact.tsx
new file mode 100644
index 0000000..1e8aef4
--- /dev/null
+++ b/app/(root)/(screens)/contact.tsx
@@ -0,0 +1,143 @@
+import { useState } from "react";
+import { Alert, Linking, ScrollView, View } from "react-native";
+import { Button } from "@/components/ui/Button";
+import { Card, InfoRow } from "@/components/ui/Card";
+import { Field } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { brand } from "@/lib/data/brand";
+import { useAuthStore } from "@/lib/stores/authStore";
+import { colors, gutter } from "@/lib/theme";
+import { CALL_PHONE, CHATWOOT_BASE, WHATSAPP_NUMBER } from "@/lib/utils";
+
+type Ticket = {
+ id: string;
+ at: string;
+ subject: string;
+ message: string;
+ status: "received" | "in_progress" | "resolved";
+};
+
+export default function ContactScreen() {
+ const user = useAuthStore((s) => s.user);
+ const [name, setName] = useState(user?.name ?? "");
+ const [subject, setSubject] = useState("Order help");
+ const [message, setMessage] = useState("");
+ const [tickets, setTickets] = useState([
+ {
+ id: "tkt_demo_1",
+ at: new Date(Date.now() - 1000 * 60 * 60 * 26).toISOString(),
+ subject: "Refill timing",
+ message: "When will my Metformin refill be ready at CMC?",
+ status: "resolved",
+ },
+ ]);
+
+ return (
+
+
+
+
+
+
+
+
+ Linking.openURL(`tel:${CALL_PHONE}`)}
+ />
+ Linking.openURL(`https://wa.me/${WHATSAPP_NUMBER}`)}
+ />
+ Linking.openURL(CHATWOOT_BASE)}
+ />
+
+
+
+
+
+ Send a message
+
+
+
+
+
+ {
+ if (!message.trim()) {
+ Alert.alert("Message required", "Tell us how we can help.");
+ return;
+ }
+ const id = `tkt_${Date.now().toString().slice(-6)}`;
+ setTickets((prev) => [
+ {
+ id,
+ at: new Date().toISOString(),
+ subject: subject.trim() || "General",
+ message: message.trim(),
+ status: "received",
+ },
+ ...prev,
+ ]);
+ setMessage("");
+ Alert.alert(
+ "Ticket created",
+ `Reference ${id}. We'll reply by phone or WhatsApp (demo — not sent to a server).`
+ );
+ }}
+ />
+
+
+
+
+
+ Your tickets
+
+ {tickets.map((t) => (
+
+
+ {t.subject} · {t.id}
+
+
+ {new Date(t.at).toLocaleString()} · {t.status}
+
+
+ {t.message}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/app/(root)/(screens)/emergency-contacts.tsx b/app/(root)/(screens)/emergency-contacts.tsx
new file mode 100644
index 0000000..68c3c59
--- /dev/null
+++ b/app/(root)/(screens)/emergency-contacts.tsx
@@ -0,0 +1,143 @@
+import { Linking, ScrollView, View } from "react-native";
+import { useState } from "react";
+import { Alert } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Badge } from "@/components/ui/Badge";
+import { Button, IconButton } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { Chip } from "@/components/ui/Chip";
+import { Field, SwitchRow } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { useEmergencyContactStore } from "@/lib/stores/emergencyContactStore";
+import { colors, gutter } from "@/lib/theme";
+
+const RELATIONSHIPS = ["spouse", "parent", "child", "sibling", "friend", "other"] as const;
+
+export default function EmergencyContactsScreen() {
+ const { t } = useTranslation();
+ const contacts = useEmergencyContactStore((s) => s.contacts);
+ const add = useEmergencyContactStore((s) => s.add);
+ const remove = useEmergencyContactStore((s) => s.remove);
+ const grace = useEmergencyContactStore((s) => s.graceMinutesDefault);
+ const setGrace = useEmergencyContactStore((s) => s.setGrace);
+ const escalationEnabled = useEmergencyContactStore((s) => s.escalationEnabled);
+ const setEscalationEnabled = useEmergencyContactStore((s) => s.setEscalationEnabled);
+ const [name, setName] = useState("");
+ const [phone, setPhone] = useState("");
+ const [relationship, setRelationship] =
+ useState<(typeof RELATIONSHIPS)[number]>("spouse");
+
+ return (
+
+
+
+
+
+
+ setGrace(Number(v) || 30)}
+ hint="Minutes to wait before notifying your contact"
+ />
+
+
+
+
+ Add contact
+
+
+
+
+ Relationship
+
+
+ {RELATIONSHIPS.map((r) => (
+ setRelationship(r)}
+ size="sm"
+ />
+ ))}
+
+ {
+ if (!name.trim() || !phone.trim()) {
+ Alert.alert("Required", "Name and phone are required.");
+ return;
+ }
+ add({ name: name.trim(), phone: phone.trim(), relationship });
+ setName("");
+ setPhone("");
+ Alert.alert("Added", `${name.trim()} can receive missed-dose alerts.`);
+ }}
+ />
+
+
+
+ {contacts.length ? "Your contacts" : "No contacts yet"}
+ {contacts.map((c) => (
+
+
+
+ {c.name}
+
+ {c.phone}
+
+
+
+
+
+ Linking.openURL(`tel:${c.phone}`)}
+ accessibilityLabel="Call"
+ />
+
+ Alert.alert("Remove contact?", c.name, [
+ { text: "Cancel", style: "cancel" },
+ {
+ text: "Remove",
+ style: "destructive",
+ onPress: () => remove(c.id),
+ },
+ ])
+ }
+ accessibilityLabel="Remove"
+ />
+
+
+ ))}
+
+
+ );
+}
diff --git a/app/(root)/(screens)/family/index.tsx b/app/(root)/(screens)/family/index.tsx
new file mode 100644
index 0000000..aa9ae7c
--- /dev/null
+++ b/app/(root)/(screens)/family/index.tsx
@@ -0,0 +1,94 @@
+import { router } from "expo-router";
+import { Alert, ScrollView, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { useFamilyStore } from "@/lib/stores/familyStore";
+import { colors, gutter } from "@/lib/theme";
+import { routes } from "@/lib/routes";
+
+export default function FamilyScreen() {
+ const { t } = useTranslation();
+ const members = useFamilyStore((s) => s.members);
+ const inviteCode = useFamilyStore((s) => s.inviteCode);
+ const acceptInvite = useFamilyStore((s) => s.acceptInvite);
+ const removeMember = useFamilyStore((s) => s.removeMember);
+ const setActiveMember = useFamilyStore((s) => s.setActiveMember);
+ const activeMemberId = useFamilyStore((s) => s.activeMemberId);
+
+ return (
+
+
+
+
+
+ Your invite code
+
+
+ {inviteCode}
+
+
+ Share this code so family can join your care circle.
+
+
+
+ router.push(routes.familyInvite)}
+ />
+
+ {members.map((m) => (
+ setActiveMember(m.id === activeMemberId ? null : m.id)}
+ style={{
+ borderColor: activeMemberId === m.id ? colors.brand : colors.line,
+ borderWidth: activeMemberId === m.id ? 1.5 : 1,
+ }}
+ >
+
+
+ {m.name}
+
+ {m.relationship}
+ {m.phone ? ` · ${m.phone}` : ""}
+
+
+
+
+
+ {m.status === "pending" ? (
+ acceptInvite(m.id)}
+ />
+ ) : null}
+
+ Alert.alert("Remove member?", m.name, [
+ { text: "Cancel", style: "cancel" },
+ { text: "Remove", style: "destructive", onPress: () => removeMember(m.id) },
+ ])
+ }
+ />
+
+
+ ))}
+
+
+ );
+}
diff --git a/app/(root)/(screens)/family/invite.tsx b/app/(root)/(screens)/family/invite.tsx
new file mode 100644
index 0000000..1df9007
--- /dev/null
+++ b/app/(root)/(screens)/family/invite.tsx
@@ -0,0 +1,85 @@
+import { Share, View } from "react-native";
+import { router } from "expo-router";
+import { useState } from "react";
+import { Alert } from "react-native";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { Chip } from "@/components/ui/Chip";
+import { Field } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { useFamilyStore } from "@/lib/stores/familyStore";
+import { colors, gutter } from "@/lib/theme";
+
+const RELATIONS = ["spouse", "child", "parent", "other"] as const;
+
+export default function FamilyInviteScreen() {
+ const addMember = useFamilyStore((s) => s.addMember);
+ const inviteCode = useFamilyStore((s) => s.inviteCode);
+ const [name, setName] = useState("");
+ const [phone, setPhone] = useState("");
+ const [relationship, setRelationship] = useState<(typeof RELATIONS)[number]>("child");
+
+ return (
+
+
+
+
+
+ Family invite code
+
+
+ {inviteCode}
+
+
+ Share.share({
+ message: `Join my Gishen family group with code ${inviteCode}`,
+ })
+ }
+ />
+
+
+ Or add by phone
+
+
+
+ Relationship
+
+
+ {RELATIONS.map((r) => (
+ setRelationship(r)}
+ size="sm"
+ />
+ ))}
+
+ {
+ if (!name.trim()) {
+ Alert.alert("Name required");
+ return;
+ }
+ addMember({ name: name.trim(), phone, relationship });
+ Alert.alert("Invited", `${name.trim()} is pending acceptance.`);
+ router.back();
+ }}
+ />
+
+
+ );
+}
diff --git a/app/(root)/(screens)/loyalty.tsx b/app/(root)/(screens)/loyalty.tsx
new file mode 100644
index 0000000..8fc025b
--- /dev/null
+++ b/app/(root)/(screens)/loyalty.tsx
@@ -0,0 +1,167 @@
+import { Share, ScrollView, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card, InfoRow, Section } from "@/components/ui/Card";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { DEMO_VOUCHER } from "@/lib/commerce";
+import { useAuthStore } from "@/lib/stores/authStore";
+import { useCartStore } from "@/lib/stores/cartStore";
+import { colors, gutter } from "@/lib/theme";
+import { router } from "expo-router";
+import { routes } from "@/lib/routes";
+import { Alert } from "react-native";
+
+const tiers = [
+ { id: "bronze", min: 0, perks: "1 pt per 10 ETB · Birthday surprise" },
+ { id: "silver", min: 300, perks: "1.25x points · Free delivery over 800 ETB" },
+ { id: "gold", min: 1000, perks: "1.5x points · Priority pharmacist consult" },
+] as const;
+
+export default function LoyaltyScreen() {
+ const { t } = useTranslation();
+ const user = useAuthStore((s) => s.user);
+ const ledger = useAuthStore((s) => s.ledger);
+ const redeemPoints = useAuthStore((s) => s.redeemPoints);
+ const setVoucher = useCartStore((s) => s.setVoucher);
+
+ const points = user?.points ?? 0;
+ const next = tiers.find((tier) => points < tier.min) ?? null;
+ const progress = next
+ ? Math.min(1, points / next.min)
+ : 1;
+
+ return (
+
+
+
+
+
+
+
+ Available points
+
+
+ {points}
+
+
+
+
+
+
+
+
+ {next
+ ? `${next.min - points} pts to ${next.id}`
+ : "You've reached Gold — enjoy premium perks"}
+
+
+
+
+
+ {tiers.map((tier, i) => (
+
+ ))}
+
+
+
+
+ Redeem rewards
+
+ Redeem 100 points for a {DEMO_VOUCHER} voucher (10% off your next order).
+
+ {user?.activeVoucher ? (
+
+ ) : null}
+ {
+ const ok = redeemPoints(100);
+ if (!ok) {
+ Alert.alert("Not enough points", "You need at least 100 points.");
+ return;
+ }
+ setVoucher(DEMO_VOUCHER);
+ Alert.alert(
+ "Voucher unlocked",
+ `${DEMO_VOUCHER} is ready in your cart / checkout.`,
+ [
+ { text: "Go to cart", onPress: () => router.push(routes.cart) },
+ { text: "OK" },
+ ]
+ );
+ }}
+ />
+
+
+
+ {t("common.referral")}
+
+ {user?.referralCode ?? "GISHEN-GUEST"}
+
+
+ Friends get 50 welcome points. You get 100 when they place their first order.
+
+
+ Share.share({
+ message: `Join Gishen Pharmacy with my code ${user?.referralCode ?? ""}. Healthcare delivered to your doorstep.`,
+ })
+ }
+ />
+
+
+
+
+ {ledger.length === 0 ? (
+
+ Points from orders will appear here.
+
+ ) : (
+ ledger.map((entry, i) => (
+ 0 ? "+" : ""}${entry.delta}`}
+ valueColor={entry.delta >= 0 ? colors.brandText : colors.danger}
+ last={i === ledger.length - 1}
+ />
+ ))
+ )}
+
+
+
+
+ );
+}
diff --git a/app/(root)/(screens)/orders/[id].tsx b/app/(root)/(screens)/orders/[id].tsx
new file mode 100644
index 0000000..6c47fa5
--- /dev/null
+++ b/app/(root)/(screens)/orders/[id].tsx
@@ -0,0 +1,240 @@
+import { Ionicons } from "@expo/vector-icons";
+import { router, useLocalSearchParams } from "expo-router";
+import { Alert, Image, ScrollView, View } from "react-native";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card, InfoRow, Section } from "@/components/ui/Card";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { getBranchById } from "@/lib/data/branches";
+import { routes } from "@/lib/routes";
+import { useOrdersStore } from "@/lib/stores/ordersStore";
+import { colors, gutter, radii } from "@/lib/theme";
+import { formatETB } from "@/lib/utils";
+
+const toneFor = {
+ requested: "neutral",
+ confirmed: "info",
+ paid: "brand",
+ dispatched: "warn",
+ delivered: "brand",
+ completed: "brand",
+ cancelled: "danger",
+} as const;
+
+export default function OrderDetailScreen() {
+ const { id } = useLocalSearchParams<{ id: string }>();
+ const order = useOrdersStore((s) => s.getById(id));
+ const cancelOrder = useOrdersStore((s) => s.cancelOrder);
+ const updateStatus = useOrdersStore((s) => s.updateStatus);
+
+ if (!order) {
+ return (
+
+
+
+
+ Order not found.
+
+
+
+ );
+ }
+
+ const branch = order.branchId ? getBranchById(order.branchId) : undefined;
+ const canCancel = !["delivered", "completed", "cancelled"].includes(order.status);
+
+ return (
+
+
+ }
+ />
+
+
+
+ {order.id}
+
+
+ {order.fulfillment === "pickup" ? "Pickup order" : "Delivery order"}
+
+
+ {order.customerName} · {order.customerPhone}
+
+ {order.notes ? (
+
+ Notes: {order.notes}
+
+ ) : null}
+
+
+
+
+ {order.items.map((item, index) => (
+
+
+
+ {item.name}
+
+ {item.unit} · Qty {item.quantity}
+ {item.requiresPrescription ? " · RX" : ""}
+
+
+ {formatETB(item.price * item.quantity)}
+
+ ))}
+
+
+
+
+
+
+
+ {order.addressLine ? (
+
+ ) : null}
+ {branch ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ {(order.discount ?? 0) > 0 ? (
+
+ ) : null}
+
+ {(order.corporateCovered ?? 0) > 0 ? (
+
+ ) : null}
+
+
+
+
+
+
+
+ {(order.timeline ?? []).map((step, index, arr) => (
+
+
+
+ {index < arr.length - 1 ? (
+
+ ) : null}
+
+
+ {step.label}
+
+ {new Date(step.at).toLocaleString()}
+
+
+
+ ))}
+
+
+
+
+ {order.status !== "cancelled" && order.status !== "delivered" ? (
+ router.push(routes.tracking(order.id))}
+ />
+ ) : null}
+ {order.status === "confirmed" || order.status === "paid" ? (
+ updateStatus(order.id, "dispatched")}
+ />
+ ) : null}
+ {canCancel ? (
+
+ Alert.alert("Cancel order?", "This cannot be undone in the demo.", [
+ { text: "Keep", style: "cancel" },
+ {
+ text: "Cancel order",
+ style: "destructive",
+ onPress: () => cancelOrder(order.id),
+ },
+ ])
+ }
+ />
+ ) : null}
+
+
+
+ );
+}
diff --git a/app/(root)/(screens)/orders/index.tsx b/app/(root)/(screens)/orders/index.tsx
new file mode 100644
index 0000000..36441ec
--- /dev/null
+++ b/app/(root)/(screens)/orders/index.tsx
@@ -0,0 +1,107 @@
+import { router } from "expo-router";
+import { Image, ScrollView, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Badge } from "@/components/ui/Badge";
+import { Card } from "@/components/ui/Card";
+import { EmptyState } from "@/components/ui/EmptyState";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { useOrdersStore } from "@/lib/stores/ordersStore";
+import { colors, gutter, radii } from "@/lib/theme";
+import { formatETB } from "@/lib/utils";
+import { routes } from "@/lib/routes";
+
+const toneFor = {
+ requested: "neutral",
+ confirmed: "info",
+ paid: "brand",
+ dispatched: "warn",
+ delivered: "brand",
+ completed: "brand",
+ cancelled: "danger",
+} as const;
+
+export default function OrdersScreen() {
+ const { t } = useTranslation();
+ const orders = useOrdersStore((s) => s.orders);
+
+ return (
+
+
+
+ {orders.length === 0 ? (
+ router.push(routes.shop)}
+ />
+ ) : (
+
+ {orders.map((o) => (
+ router.push(routes.orderDetail(o.id))}>
+
+
+
+ {o.fulfillment === "pickup" ? "Pickup" : "Delivery"} · {o.areaLabel}
+
+
+ {new Date(o.createdAt).toLocaleString()} · {o.paymentMethod}
+
+
+
+
+
+
+ {o.items.slice(0, 3).map((item) => (
+
+ ))}
+ {o.items.length > 3 ? (
+
+ +{o.items.length - 3}
+
+ ) : null}
+
+
+
+ {formatETB(o.total)}
+
+ View details
+
+
+
+ ))}
+
+ )}
+
+
+ );
+}
diff --git a/app/(root)/(screens)/prescription/[id].tsx b/app/(root)/(screens)/prescription/[id].tsx
new file mode 100644
index 0000000..3572526
--- /dev/null
+++ b/app/(root)/(screens)/prescription/[id].tsx
@@ -0,0 +1,211 @@
+import { Ionicons } from "@expo/vector-icons";
+import { router, useLocalSearchParams } from "expo-router";
+import { Image, ScrollView, View } from "react-native";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card, InfoRow, Section } from "@/components/ui/Card";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { products } from "@/lib/data/products";
+import { useCartStore } from "@/lib/stores/cartStore";
+import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
+import { colors, gutter, radii } from "@/lib/theme";
+import { routes } from "@/lib/routes";
+
+const statusTone = {
+ submitted: "neutral",
+ under_review: "warn",
+ approved: "brand",
+ queried: "info",
+ rejected: "danger",
+ filled: "brand",
+} as const;
+
+const lineTone = {
+ ready: "brand",
+ review: "warn",
+ unavailable: "danger",
+} as const;
+
+export default function PrescriptionDetailScreen() {
+ const { id } = useLocalSearchParams<{ id: string }>();
+ const rx = usePrescriptionStore((s) => s.prescriptions.find((p) => p.id === id));
+ const reminders = usePrescriptionStore((s) =>
+ s.reminders.filter((r) => r.prescriptionId === id)
+ );
+ const markRefilled = usePrescriptionStore((s) => s.markRefilled);
+ const updateRxStatus = usePrescriptionStore((s) => s.updateRxStatus);
+ const addProduct = useCartStore((s) => s.addProduct);
+
+ if (!rx) {
+ return (
+
+
+
+
+ Prescription not found.
+
+
+
+ );
+ }
+
+ const dueIn = (() => {
+ if (!rx.lastFilledAt) return null;
+ const due = new Date(rx.lastFilledAt);
+ due.setDate(due.getDate() + rx.daysSupply);
+ return Math.ceil((due.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
+ })();
+
+ return (
+
+
+
+ {rx.imageUris[0] ? (
+
+ ) : null}
+
+
+
+
+ {rx.medicineName}
+
+ For {rx.patientName}
+
+
+
+
+ {dueIn !== null ? (
+
+ {dueIn <= 0 ? "Refill overdue" : `Refill in ${dueIn} days`}
+
+ ) : (
+
+ Awaiting first fill
+
+ )}
+
+
+
+
+ {rx.medicines.map((m, i) => (
+
+
+
+ {m.name}
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+ {rx.notes ? : null}
+
+
+
+
+ {reminders.length === 0 ? (
+
+
+ No reminders yet. Set times so we can nudge you — and escalate if a dose is missed.
+
+
+ ) : (
+ reminders.map((r) => (
+
+ {r.medicineName}
+
+ {r.times.join(" · ")} · {r.graceMinutes} min grace
+ {r.escalateOnMiss ? " · escalate if missed" : ""}
+
+
+ ))
+ )}
+ router.push(routes.rxCalendar(rx.id))}
+ style={{ marginTop: 8 }}
+ />
+
+
+
+ {
+ const match = products.find((p) =>
+ rx.medicineName.toLowerCase().includes(p.name.toLowerCase().split(" ")[0])
+ );
+ if (match) addProduct(match);
+ router.push(routes.cart);
+ }}
+ />
+ markRefilled(rx.id)}
+ />
+ {rx.status === "under_review" || rx.status === "submitted" ? (
+ updateRxStatus(rx.id, "approved")}
+ />
+ ) : null}
+
+
+
+ );
+}
diff --git a/app/(root)/(screens)/prescription/calendar/[id].tsx b/app/(root)/(screens)/prescription/calendar/[id].tsx
new file mode 100644
index 0000000..0c92b8d
--- /dev/null
+++ b/app/(root)/(screens)/prescription/calendar/[id].tsx
@@ -0,0 +1,265 @@
+import { useLocalSearchParams } from "expo-router";
+import { useMemo, useState } from "react";
+import { Alert, ScrollView, View } from "react-native";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { Chip } from "@/components/ui/Chip";
+import { Field, SwitchRow } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { EmptyState } from "@/components/ui/EmptyState";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import {
+ scheduleDoseReminder,
+ scheduleEscalationCheck,
+} from "@/lib/notifications";
+import { useEmergencyContactStore } from "@/lib/stores/emergencyContactStore";
+import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
+import { colors, gutter } from "@/lib/theme";
+
+const PRESETS = ["08:00", "12:00", "14:00", "18:00", "20:00"] as const;
+
+export default function RxCalendarScreen() {
+ const { id } = useLocalSearchParams<{ id: string }>();
+ const rx = usePrescriptionStore((s) => s.prescriptions.find((p) => p.id === id));
+ const upsertReminder = usePrescriptionStore((s) => s.upsertReminder);
+ const schedulePendingDose = usePrescriptionStore((s) => s.schedulePendingDose);
+ const confirmDose = usePrescriptionStore((s) => s.confirmDose);
+ const escalateDose = usePrescriptionStore((s) => s.escalateDose);
+ const doseLogs = usePrescriptionStore((s) => s.doseLogs);
+ const reminder = usePrescriptionStore((s) =>
+ s.reminders.find((r) => r.prescriptionId === id)
+ );
+ const grace = useEmergencyContactStore((s) => s.graceMinutesDefault);
+ const setGrace = useEmergencyContactStore((s) => s.setGrace);
+ const escalationEnabled = useEmergencyContactStore((s) => s.escalationEnabled);
+ const setEscalationEnabled = useEmergencyContactStore((s) => s.setEscalationEnabled);
+ const contacts = useEmergencyContactStore((s) => s.contacts);
+ const markEscalated = useEmergencyContactStore((s) => s.markEscalated);
+ const [times, setTimes] = useState(reminder?.times.join(",") || "08:00,20:00");
+ const [pendingLogId, setPendingLogId] = useState(null);
+
+ const reminderId = `rem_${id}`;
+ const relatedLogs = useMemo(
+ () => doseLogs.filter((l) => l.reminderId === reminderId).slice(0, 8),
+ [doseLogs, reminderId]
+ );
+
+ if (!rx) {
+ return (
+
+
+
+ );
+ }
+
+ const togglePreset = (t: string) => {
+ const list = times
+ .split(",")
+ .map((s) => s.trim())
+ .filter(Boolean);
+ if (list.includes(t)) {
+ setTimes(list.filter((x) => x !== t).join(","));
+ } else {
+ setTimes([...list, t].sort().join(","));
+ }
+ };
+
+ const saveAndSchedule = async () => {
+ const parsed = times
+ .split(",")
+ .map((s) => s.trim())
+ .filter(Boolean);
+ if (!parsed.length) {
+ Alert.alert("Times required", "Pick at least one reminder time.");
+ return;
+ }
+ upsertReminder({
+ id: reminderId,
+ prescriptionId: rx.id,
+ medicineName: rx.medicineName,
+ times: parsed,
+ daysOfWeek: [0, 1, 2, 3, 4, 5, 6],
+ graceMinutes: grace,
+ escalateOnMiss: escalationEnabled,
+ enabled: true,
+ });
+ await scheduleDoseReminder({
+ title: `Time for ${rx.medicineName}`,
+ body: "Tap to confirm you took your dose",
+ secondsFromNow: 15,
+ data: { prescriptionId: rx.id, type: "dose" },
+ });
+ const log = schedulePendingDose(reminderId);
+ setPendingLogId(log.id);
+
+ if (escalationEnabled && contacts.length) {
+ await scheduleEscalationCheck({
+ title: "Dose not confirmed",
+ body: `Notifying ${contacts[0].name} if still unconfirmed`,
+ graceSeconds: Math.max(20, grace * 60),
+ data: { logId: log.id, type: "escalation" },
+ });
+ setTimeout(() => {
+ const current = usePrescriptionStore
+ .getState()
+ .doseLogs.find((l) => l.id === log.id);
+ if (current?.status === "pending") {
+ escalateDose(log.id);
+ markEscalated();
+ Alert.alert("Emergency", `${contacts[0].name} would be notified (mock SMS/push)`);
+ }
+ }, Math.max(25000, grace * 1000));
+ } else if (escalationEnabled && !contacts.length) {
+ Alert.alert(
+ "No emergency contact",
+ "Add a contact under Profile → Emergency contacts for escalation."
+ );
+ }
+
+ Alert.alert("Scheduled", `Reminders at ${parsed.join(", ")}. Demo push in ~15s.`);
+ };
+
+ return (
+
+
+
+
+
+ Patient
+
+
+ {rx.patientName || "Self"}
+
+
+ {rx.status} · {rx.daysSupply} day supply
+
+
+
+
+ Dose times
+
+ Tap presets or edit the comma-separated list
+
+
+ {PRESETS.map((p) => {
+ const selected = times
+ .split(",")
+ .map((s) => s.trim())
+ .includes(p);
+ return (
+ togglePreset(p)}
+ size="sm"
+ />
+ );
+ })}
+
+
+
+
+
+
+
+
+
+ setGrace(Number(v) || 30)}
+ />
+
+
+
+ {pendingLogId ? (
+
+ Confirm this dose
+
+ Demo reminder is active. Mark taken or snooze.
+
+
+ {
+ confirmDose(pendingLogId);
+ setPendingLogId(null);
+ Alert.alert("Logged", "Dose confirmed");
+ }}
+ />
+
+ scheduleDoseReminder({
+ title: `Snoozed: ${rx.medicineName}`,
+ body: "Reminder",
+ secondsFromNow: 600,
+ })
+ }
+ />
+
+
+ ) : null}
+
+
+
+ Recent dose logs
+ {relatedLogs.length === 0 && doseLogs.length === 0 ? (
+
+ No logs yet. Schedule a reminder to start tracking.
+
+ ) : (
+ (relatedLogs.length ? relatedLogs : doseLogs.slice(0, 8)).map((l) => (
+
+
+
+
+ {new Date(l.scheduledAt).toLocaleString()}
+
+
+
+ ))
+ )}
+
+
+ );
+}
diff --git a/app/(root)/(screens)/prescription/list.tsx b/app/(root)/(screens)/prescription/list.tsx
new file mode 100644
index 0000000..110cd92
--- /dev/null
+++ b/app/(root)/(screens)/prescription/list.tsx
@@ -0,0 +1,109 @@
+import { router } from "expo-router";
+import { ScrollView, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { EmptyState } from "@/components/ui/EmptyState";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
+import { colors, gutter } from "@/lib/theme";
+import { routes } from "@/lib/routes";
+
+const statusTone = {
+ submitted: "neutral",
+ under_review: "warn",
+ approved: "brand",
+ queried: "info",
+ rejected: "danger",
+ filled: "brand",
+} as const;
+
+export default function RxListScreen() {
+ const { t } = useTranslation();
+ const prescriptions = usePrescriptionStore((s) => s.prescriptions);
+
+ return (
+
+
+
+ router.push(routes.rxScan)}
+ />
+
+ {prescriptions.length === 0 ? (
+ router.push(routes.rxScan)}
+ />
+ ) : (
+
+ {prescriptions.map((rx) => {
+ const dueIn = (() => {
+ if (!rx.lastFilledAt) return null;
+ const due = new Date(rx.lastFilledAt);
+ due.setDate(due.getDate() + rx.daysSupply);
+ return Math.ceil((due.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
+ })();
+
+ return (
+ router.push(routes.rxDetail(rx.id))}>
+
+
+ {rx.medicineName}
+
+ {rx.patientName} · {rx.medicines.length} item
+ {rx.medicines.length === 1 ? "" : "s"}
+
+
+
+
+ {dueIn !== null ? (
+
+ {dueIn <= 0 ? "Refill overdue" : `Refill in ${dueIn} days`}
+
+ ) : (
+
+ Waiting for first fill
+
+ )}
+
+ Tap for details, reminders and reorder
+
+
+ );
+ })}
+
+ )}
+
+
+ );
+}
diff --git a/app/(root)/(screens)/prescription/review.tsx b/app/(root)/(screens)/prescription/review.tsx
new file mode 100644
index 0000000..379771d
--- /dev/null
+++ b/app/(root)/(screens)/prescription/review.tsx
@@ -0,0 +1,222 @@
+import { router } from "expo-router";
+import { useMemo, useState } from "react";
+import { Alert, Image, ScrollView, View } from "react-native";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { Chip } from "@/components/ui/Chip";
+import { Field } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { products } from "@/lib/data/products";
+import { routes } from "@/lib/routes";
+import { useAuthStore } from "@/lib/stores/authStore";
+import { useCartStore } from "@/lib/stores/cartStore";
+import { useFamilyStore } from "@/lib/stores/familyStore";
+import { useLocationStore } from "@/lib/stores/locationStore";
+import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
+import { colors, gutter, radii } from "@/lib/theme";
+
+function matchStatus(name: string): "ready" | "review" | "unavailable" {
+ const hit = products.find((p) =>
+ p.name.toLowerCase().includes(name.trim().toLowerCase())
+ );
+ if (!hit) return "review";
+ if (!hit.inStock) return "unavailable";
+ return "ready";
+}
+
+export default function RxReviewScreen() {
+ const draftImages = usePrescriptionStore((s) => s.draftImages);
+ const setDraftImages = usePrescriptionStore((s) => s.setDraftImages);
+ const addPrescription = usePrescriptionStore((s) => s.addPrescription);
+ const addProduct = useCartStore((s) => s.addProduct);
+ const setFulfillment = useLocationStore((s) => s.setFulfillment);
+ const user = useAuthStore((s) => s.user);
+ const members = useFamilyStore((s) => s.members);
+ const activeMemberId = useFamilyStore((s) => s.activeMemberId);
+ const activeMember = members.find((m) => m.id === activeMemberId);
+
+ const [patientName, setPatientName] = useState(
+ activeMember?.name || user?.name || ""
+ );
+ const [memberId, setMemberId] = useState(activeMemberId);
+ const [medicineName, setMedicineName] = useState("Metformin 500mg");
+ const [daysSupply, setDaysSupply] = useState("30");
+ const [list, setList] = useState("Metformin 500mg, Vitamin B12");
+ const [notes, setNotes] = useState("");
+
+ const medicines = useMemo(() => {
+ return list
+ .split(",")
+ .map((s) => s.trim())
+ .filter(Boolean)
+ .map((name) => ({ name, status: matchStatus(name) }));
+ }, [list]);
+
+ const save = (toCart: boolean) => {
+ if (!draftImages.length) {
+ Alert.alert("Image required", "Scan or upload at least one prescription photo first.");
+ return;
+ }
+ if (!patientName.trim() || !medicineName.trim()) {
+ Alert.alert("Missing", "Patient and primary medicine are required.");
+ return;
+ }
+ const meds =
+ medicines.length > 0
+ ? medicines
+ : [{ name: medicineName, status: matchStatus(medicineName) }];
+ const rx = addPrescription({
+ patientName: patientName.trim(),
+ memberId,
+ medicineName: medicineName.trim(),
+ medicines: meds,
+ imageUris: draftImages,
+ daysSupply: Number(daysSupply) || 30,
+ lastFilledAt: null,
+ notes: notes.trim(),
+ });
+ if (toCart) {
+ meds
+ .filter((m) => m.status === "ready")
+ .forEach((m) => {
+ const p = products.find((x) =>
+ x.name.toLowerCase().includes(m.name.toLowerCase().split(" ")[0])
+ );
+ if (p) addProduct(p);
+ });
+ setFulfillment("pickup");
+ }
+ setDraftImages([]);
+ Alert.alert("Saved", "Prescription submitted for pharmacist review", [
+ { text: "Open details", onPress: () => router.replace(routes.rxDetail(rx.id)) },
+ { text: "Reminders", onPress: () => router.replace(routes.rxCalendar(rx.id)) },
+ { text: "List", onPress: () => router.replace(routes.rxList) },
+ ]);
+ };
+
+ return (
+
+
+
+ {draftImages.length ? (
+
+ {draftImages.map((uri) => (
+
+ ))}
+
+ ) : (
+
+ No images attached
+
+ Go back to scan or upload a prescription photo.
+
+ router.replace(routes.rxScan)}
+ />
+
+ )}
+
+
+
+ Patient
+
+
+ {
+ setMemberId(null);
+ setPatientName(user?.name || "");
+ }}
+ />
+ {members
+ .filter((m) => m.status === "accepted")
+ .map((m) => (
+ {
+ setMemberId(m.id);
+ setPatientName(m.name);
+ }}
+ />
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+ Availability preview
+
+ {(medicines.length ? medicines : [{ name: medicineName || "—", status: "review" as const }]).map(
+ (m) => (
+
+ {m.name}
+
+
+ )
+ )}
+
+
+ save(false)} />
+ save(true)}
+ />
+
+
+ );
+}
diff --git a/app/(root)/(screens)/prescription/scan.tsx b/app/(root)/(screens)/prescription/scan.tsx
new file mode 100644
index 0000000..d885ec1
--- /dev/null
+++ b/app/(root)/(screens)/prescription/scan.tsx
@@ -0,0 +1,196 @@
+import { CameraView, useCameraPermissions } from "expo-camera";
+import * as ImagePicker from "expo-image-picker";
+import { router } from "expo-router";
+import { useRef, useState } from "react";
+import { Alert, Image, Pressable, ScrollView, View } from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { Ionicons } from "@expo/vector-icons";
+import { useTranslation } from "react-i18next";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
+import { colors, gutter } from "@/lib/theme";
+import { routes } from "@/lib/routes";
+
+export default function RxScanScreen() {
+ const insets = useSafeAreaInsets();
+ const { t } = useTranslation();
+ const [permission, requestPermission] = useCameraPermissions();
+ const cameraRef = useRef(null);
+ const draftImages = usePrescriptionStore((s) => s.draftImages);
+ const setDraftImages = usePrescriptionStore((s) => s.setDraftImages);
+ const [ready, setReady] = useState(false);
+
+ const capture = async () => {
+ const photo = await cameraRef.current?.takePictureAsync({ quality: 0.7 });
+ if (photo?.uri) setDraftImages([...draftImages, photo.uri]);
+ };
+
+ const pick = async () => {
+ const res = await ImagePicker.launchImageLibraryAsync({
+ allowsMultipleSelection: true,
+ quality: 0.7,
+ });
+ if (!res.canceled) {
+ setDraftImages([...draftImages, ...res.assets.map((a) => a.uri)]);
+ }
+ };
+
+ const removeAt = (uri: string) => {
+ setDraftImages(draftImages.filter((u) => u !== uri));
+ };
+
+ if (!permission?.granted) {
+ return (
+
+
+ Scan prescription
+
+ Allow camera access to photograph your prescription, or upload existing photos.
+
+
+
+ Tips: place the Rx on a flat surface, include the full page, and avoid glare.
+
+
+
+
+ {draftImages.length ? (
+ router.push(routes.rxReview)}
+ />
+ ) : null}
+ router.back()} />
+
+
+ );
+ }
+
+ return (
+
+ setReady(true)}
+ >
+
+ router.back()} hitSlop={8}>
+
+
+
+ {t("common.scanRx")}
+
+
+ {draftImages.length} saved
+
+
+
+
+
+ Align the full prescription inside the frame
+
+
+
+
+ {draftImages.map((uri) => (
+ removeAt(uri)}>
+
+
+ ))}
+
+ {draftImages.length ? (
+
+ Long-press a thumbnail to remove
+
+ ) : null}
+
+
+
+
+
+ {
+ if (!draftImages.length) {
+ Alert.alert("Add a photo", "Capture or upload at least one image first.");
+ return;
+ }
+ router.push(routes.rxReview);
+ }}
+ accessibilityLabel="Continue to review"
+ >
+
+
+
+
+
+
+ );
+}
diff --git a/app/(root)/(screens)/product/[id].tsx b/app/(root)/(screens)/product/[id].tsx
new file mode 100644
index 0000000..8e9bbab
--- /dev/null
+++ b/app/(root)/(screens)/product/[id].tsx
@@ -0,0 +1,439 @@
+import { Ionicons } from "@expo/vector-icons";
+import { router, useLocalSearchParams } from "expo-router";
+import { useMemo, useState } from "react";
+import {
+ Image,
+ Pressable,
+ ScrollView,
+ View,
+} from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { useTranslation } from "react-i18next";
+import { Badge, Price, Rating, StockLabel } from "@/components/ui/Badge";
+import { Button, IconButton } from "@/components/ui/Button";
+import { Card, InfoRow, Section } from "@/components/ui/Card";
+import { Chip } from "@/components/ui/Chip";
+import { QtyStepper } from "@/components/ui/QtyStepper";
+import { StickyBar } from "@/components/ui/StickyBar";
+import { Text } from "@/components/ui/Text";
+import { branches } from "@/lib/data/branches";
+import { getDrugFacts, getReviewBreakdown } from "@/lib/data/clinical";
+import { products } from "@/lib/data/products";
+import { useCartStore } from "@/lib/stores/cartStore";
+import { useFavoritesStore } from "@/lib/stores/favoritesStore";
+import { colors, gutter, radii, space } from "@/lib/theme";
+import { formatETB } from "@/lib/utils";
+import { routes } from "@/lib/routes";
+
+export default function ProductDetailScreen() {
+ const { id } = useLocalSearchParams<{ id: string }>();
+ const product = products.find((p) => p.id === id) ?? products[0];
+ const facts = useMemo(() => getDrugFacts(product), [product]);
+ const reviews = useMemo(() => getReviewBreakdown(product), [product]);
+ const [qty, setQty] = useState(1);
+ const [dose, setDose] = useState(facts.dosages[0] ?? "");
+ const [tab, setTab] = useState<"details" | "pharmacy">("details");
+ const [more, setMore] = useState(false);
+ const insets = useSafeAreaInsets();
+ const { t } = useTranslation();
+ const addProduct = useCartStore((s) => s.addProduct);
+ const toggle = useFavoritesStore((s) => s.toggle);
+ const liked = useFavoritesStore((s) => s.has(product.id));
+
+ const addToCart = () => {
+ addProduct(product, qty);
+ };
+
+ return (
+
+
+
+
+ router.back()} />
+ toggle(product.id)}
+ color={liked ? colors.danger : colors.ink}
+ />
+
+
+
+
+
+ {product.requiresPrescription ? (
+
+ ) : (
+
+ )}
+
+
+
+ {product.name}
+
+ {product.brand} · {product.unit}
+
+
+
+
+
+
+
+ {facts.dosages.length > 0 ? (
+
+
+ Strength
+
+
+ {facts.dosages.map((d) => (
+ setDose(d)}
+ />
+ ))}
+
+
+ ) : null}
+
+
+
+
+
+
+
+
+
+
+ Same-day delivery in Addis Ababa
+
+
+
+
+
+ Pharmacist-verified · 30-day return policy
+
+
+
+
+ {
+ addToCart();
+ router.push(routes.cart);
+ }}
+ disabled={!product.inStock}
+ />
+
+
+
+
+ {(["details", "pharmacy"] as const).map((key) => (
+ setTab(key)}
+ style={{
+ flex: 1,
+ alignItems: "center",
+ paddingVertical: 10,
+ borderRadius: radii.pill,
+ backgroundColor: tab === key ? colors.surface : "transparent",
+ }}
+ >
+
+ {key === "details" ? "Details" : "Pharmacy"}
+
+
+ ))}
+
+
+
+ {tab === "details" ? (
+
+
+
+ {more ? product.description : `${product.description.slice(0, 140)}…`}
+
+ setMore(!more)} style={{ marginTop: 6 }}>
+
+ {more ? "Show less" : "Read more"}
+
+
+
+
+
+
+
+
+ Common (mild)
+
+
+ {facts.sideEffects.mild.map((s) => (
+
+ ))}
+
+ {facts.sideEffects.severe.length > 0 ? (
+ <>
+
+ Severe (rare)
+
+
+ {facts.sideEffects.severe.map((s) => (
+
+ ))}
+
+ >
+ ) : null}
+
+
+
+
+ {facts.storage.map((note) => (
+
+
+
+
+
+
+ {note.title}
+
+ {note.body}
+
+
+
+
+ ))}
+
+
+
+
+
+ {facts.directions.map((step, index) => (
+
+
+
+
+ {index + 1}
+
+
+ {index < facts.directions.length - 1 ? (
+
+ ) : null}
+
+
+ {step.title}
+
+ {step.body}
+
+
+
+ ))}
+
+
+
+
+
+
+ {product.rating.toFixed(1)}
+
+ {product.reviews} reviews
+
+
+
+ {reviews.map((row) => {
+ const max = reviews[0]?.count || 1;
+ return (
+
+
+ {row.stars}
+
+
+
+
+
+ );
+ })}
+
+
+
+
+
+ Pharmacist tip
+
+ {facts.advice}
+
+
+
+ ) : (
+
+
+ {branches.slice(0, 4).map((branch, index) => (
+ router.push(routes.branches)}
+ style={{ marginTop: index === 0 ? 0 : 10 }}
+ >
+
+
+ {branch.name}
+
+ {branch.area}
+
+
+ {branch.hours}
+ {branch.pickupAvailable ? " · Pickup available" : ""}
+
+
+ {index === 0 ? (
+
+ ) : (
+
+ )}
+
+
+ ))}
+ router.push(routes.branches)}
+ style={{ marginTop: 14 }}
+ />
+
+
+ )}
+
+
+
+
+
+ {product.name}
+
+
+ {formatETB(product.price * qty)}
+
+
+
+
+
+ );
+}
diff --git a/app/(root)/(screens)/profiles/join.tsx b/app/(root)/(screens)/profiles/join.tsx
new file mode 100644
index 0000000..c11f5bc
--- /dev/null
+++ b/app/(root)/(screens)/profiles/join.tsx
@@ -0,0 +1,60 @@
+import { router } from "expo-router";
+import { useState } from "react";
+import { Alert, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { Chip } from "@/components/ui/Chip";
+import { Field } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { useProfileModeStore } from "@/lib/stores/profileModeStore";
+import { colors, gutter } from "@/lib/theme";
+
+const DEMO_CODES = ["GISHEN-BANK", "GISHEN-NGO"] as const;
+
+export default function JoinOrgScreen() {
+ const { t } = useTranslation();
+ const joinOrg = useProfileModeStore((s) => s.joinOrg);
+ const [code, setCode] = useState("");
+
+ return (
+
+
+
+
+
+ Enter the join code from your HR or organisation admin. Demo codes work offline.
+
+
+ {DEMO_CODES.map((c) => (
+ setCode(c)} size="sm" />
+ ))}
+
+
+
+
+
+ {
+ const res = joinOrg(code);
+ Alert.alert(res.ok ? "Joined" : "Failed", res.message);
+ if (res.ok) router.back();
+ }}
+ />
+
+
+ );
+}
diff --git a/app/(root)/(screens)/profiles/switch.tsx b/app/(root)/(screens)/profiles/switch.tsx
new file mode 100644
index 0000000..6bf6417
--- /dev/null
+++ b/app/(root)/(screens)/profiles/switch.tsx
@@ -0,0 +1,134 @@
+import { Ionicons } from "@expo/vector-icons";
+import { router } from "expo-router";
+import { useTranslation } from "react-i18next";
+import { Pressable, ScrollView, View } from "react-native";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { routes } from "@/lib/routes";
+import { useProfileModeStore } from "@/lib/stores/profileModeStore";
+import { colors, gutter } from "@/lib/theme";
+import { formatETB } from "@/lib/utils";
+
+export default function ProfileSwitchScreen() {
+ const { t } = useTranslation();
+ const mode = useProfileModeStore((s) => s.mode);
+ const setMode = useProfileModeStore((s) => s.setMode);
+ const memberships = useProfileModeStore((s) => s.memberships);
+ const setActiveOrg = useProfileModeStore((s) => s.setActiveOrg);
+ const activeOrgId = useProfileModeStore((s) => s.activeOrgId);
+
+ return (
+
+
+
+ {
+ setMode("personal");
+ setActiveOrg(null);
+ }}
+ style={cardStyle(mode === "personal")}
+ >
+
+
+
+
+
+ {t("common.personal")}
+
+ Retail shopping, loyalty points, family
+
+
+ {mode === "personal" ? : null}
+
+
+
+ {memberships.map((m) => {
+ const active = mode === "corporate" && activeOrgId === m.orgId;
+ return (
+ setActiveOrg(m.orgId)}
+ style={cardStyle(active)}
+ >
+
+
+
+
+
+ {m.orgName}
+
+ {m.planName}
+
+
+ {formatETB(m.remainingAllowance)} allowance left
+
+
+ {active ? : null}
+
+
+ );
+ })}
+
+ {!memberships.length ? (
+
+
+ No organisations yet. Join with a demo code from your HR team.
+
+ router.push(routes.profileJoin)}
+ style={{ marginTop: 12 }}
+ />
+
+ ) : (
+ router.push(routes.profileJoin)}
+ />
+ )}
+
+
+ );
+}
+
+function cardStyle(selected: boolean) {
+ return {
+ backgroundColor: colors.surface,
+ borderRadius: 20,
+ padding: 16,
+ borderWidth: selected ? 2 : 1,
+ borderColor: selected ? colors.brand : colors.line,
+ };
+}
diff --git a/app/(root)/(screens)/search.tsx b/app/(root)/(screens)/search.tsx
new file mode 100644
index 0000000..e45d73b
--- /dev/null
+++ b/app/(root)/(screens)/search.tsx
@@ -0,0 +1,111 @@
+import { router, useLocalSearchParams } from "expo-router";
+import { useMemo, useState } from "react";
+import { FlatList, Pressable, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Chip, ChipRow } from "@/components/ui/Chip";
+import { EmptyState } from "@/components/ui/EmptyState";
+import { AppHeader } from "@/components/ui/Header";
+import { ProductRow } from "@/components/ui/ProductCard";
+import { Screen } from "@/components/ui/Screen";
+import { SearchField } from "@/components/ui/SearchField";
+import { Text } from "@/components/ui/Text";
+import { products, searchProducts } from "@/lib/data/products";
+import { categories, routes } from "@/lib/routes";
+import { colors, gutter } from "@/lib/theme";
+
+const recent = ["Panadol", "Metformin", "Vitamin C", "Cough syrup", "Glucose meter"];
+
+export default function SearchScreen() {
+ const { t } = useTranslation();
+ const params = useLocalSearchParams<{ q?: string }>();
+ const [q, setQ] = useState(params.q ?? "");
+
+ const results = useMemo(() => (q.trim() ? searchProducts(q) : []), [q]);
+
+ return (
+
+
+
+ setQ("")}
+ autoFocus
+ placeholder={t("common.search")}
+ />
+
+
+ {!q.trim() ? (
+
+ Recent searches
+
+ {recent.map((term) => (
+ setQ(term)}
+ style={{ flexDirection: "row", alignItems: "center", gap: 10 }}
+ >
+
+ {term}
+
+
+ ))}
+
+
+
+ Browse by category
+
+
+ {categories.map((c) => (
+
+ router.push({ pathname: routes.shop, params: { category: c.id } })
+ }
+ />
+ ))}
+
+
+
+ Popular right now
+
+
+ {products
+ .filter((p) => p.badge === "bestseller")
+ .slice(0, 4)
+ .map((p) => (
+
+ ))}
+
+
+ ) : (
+ i.id}
+ contentContainerStyle={{
+ paddingHorizontal: gutter,
+ paddingTop: 16,
+ paddingBottom: 40,
+ gap: 10,
+ }}
+ ListEmptyComponent={
+
+ }
+ ListHeaderComponent={
+
+ {results.length} result{results.length === 1 ? "" : "s"}
+
+ }
+ renderItem={({ item }) => }
+ />
+ )}
+
+ );
+}
diff --git a/app/(root)/(screens)/shop.tsx b/app/(root)/(screens)/shop.tsx
new file mode 100644
index 0000000..bef7bc8
--- /dev/null
+++ b/app/(root)/(screens)/shop.tsx
@@ -0,0 +1,91 @@
+import { useLocalSearchParams } from "expo-router";
+import { useMemo, useState } from "react";
+import { FlatList, useWindowDimensions, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Chip, ChipRow } from "@/components/ui/Chip";
+import { EmptyState } from "@/components/ui/EmptyState";
+import { AppHeader } from "@/components/ui/Header";
+import { ProductCard, GRID_CARD_GAP } from "@/components/ui/ProductCard";
+import { Screen } from "@/components/ui/Screen";
+import { SearchField } from "@/components/ui/SearchField";
+import { products } from "@/lib/data/products";
+import { categories } from "@/lib/routes";
+import { gutter } from "@/lib/theme";
+
+export default function ShopScreen() {
+ const { t } = useTranslation();
+ const params = useLocalSearchParams<{ q?: string; category?: string }>();
+ const [q, setQ] = useState(params.q ?? "");
+ const [category, setCategory] = useState(params.category ?? "");
+ const { width } = useWindowDimensions();
+ const cardWidth = (width - gutter * 2 - GRID_CARD_GAP) / 2;
+
+ const data = useMemo(() => {
+ return products.filter((p) => {
+ const catOk = !category || p.category === category;
+ const qOk =
+ !q ||
+ p.name.toLowerCase().includes(q.toLowerCase()) ||
+ p.brand.toLowerCase().includes(q.toLowerCase()) ||
+ p.description.toLowerCase().includes(q.toLowerCase());
+ return catOk && qOk;
+ });
+ }, [q, category]);
+
+ return (
+
+
+
+ setQ("")}
+ placeholder={t("common.search")}
+ />
+
+
+ setCategory("")}
+ />
+ {categories.map((c) => (
+ setCategory(c.id)}
+ icon={c.icon}
+ />
+ ))}
+
+ i.id}
+ showsVerticalScrollIndicator={false}
+ contentContainerStyle={{
+ paddingHorizontal: gutter,
+ paddingTop: 16,
+ paddingBottom: 40,
+ gap: GRID_CARD_GAP,
+ }}
+ columnWrapperStyle={{ gap: GRID_CARD_GAP }}
+ ListEmptyComponent={
+
+ }
+ renderItem={({ item }) => }
+ />
+
+ );
+}
diff --git a/app/(root)/(screens)/subscriptions/index.tsx b/app/(root)/(screens)/subscriptions/index.tsx
new file mode 100644
index 0000000..2fea35a
--- /dev/null
+++ b/app/(root)/(screens)/subscriptions/index.tsx
@@ -0,0 +1,255 @@
+import { useMemo, useState } from "react";
+import { Alert, ScrollView, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card } from "@/components/ui/Card";
+import { Chip, Segmented } from "@/components/ui/Chip";
+import { Field } from "@/components/ui/Field";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { products } from "@/lib/data/products";
+import { useFamilyStore } from "@/lib/stores/familyStore";
+import { useLocationStore, type Fulfillment, type PaymentMethod } from "@/lib/stores/locationStore";
+import { useSubscriptionStore } from "@/lib/stores/subscriptionStore";
+import { colors, gutter } from "@/lib/theme";
+
+const FREQUENCIES = [
+ { days: 7, label: "Weekly" },
+ { days: 14, label: "Every 2 weeks" },
+ { days: 30, label: "Monthly" },
+ { days: 60, label: "Every 2 months" },
+ { days: 90, label: "Every 3 months" },
+];
+
+export default function SubscriptionsScreen() {
+ const { t } = useTranslation();
+ const items = useSubscriptionStore((s) => s.items);
+ const add = useSubscriptionStore((s) => s.add);
+ const pause = useSubscriptionStore((s) => s.pause);
+ const resume = useSubscriptionStore((s) => s.resume);
+ const cancel = useSubscriptionStore((s) => s.cancel);
+ const paymentPref = useLocationStore((s) => s.paymentPreference);
+ const fulfillmentPref = useLocationStore((s) => s.fulfillment);
+ const members = useFamilyStore((s) => s.members);
+
+ const refillCandidates = useMemo(
+ () =>
+ products.filter(
+ (p) =>
+ p.requiresPrescription ||
+ p.category === "diabetic" ||
+ p.category === "vitamins" ||
+ p.badge === "bestseller"
+ ),
+ []
+ );
+
+ const [showCreate, setShowCreate] = useState(false);
+ const [productId, setProductId] = useState(refillCandidates[0]?.id ?? products[0].id);
+ const [qty, setQty] = useState("1");
+ const [frequencyDays, setFrequencyDays] = useState(30);
+ const [fulfillment, setFulfillment] = useState(fulfillmentPref);
+ const [payment, setPayment] = useState(
+ paymentPref === "pay_at_branch" && fulfillmentPref === "delivery"
+ ? "chapa"
+ : paymentPref
+ );
+ const [memberId, setMemberId] = useState(null);
+ const [query, setQuery] = useState("");
+
+ const filtered = refillCandidates.filter(
+ (p) =>
+ !query ||
+ p.name.toLowerCase().includes(query.toLowerCase()) ||
+ p.brand.toLowerCase().includes(query.toLowerCase())
+ );
+ const selected = products.find((p) => p.id === productId) ?? products[0];
+
+ return (
+
+
+
+ {!showCreate ? (
+ setShowCreate(true)}
+ />
+ ) : (
+
+
+ New subscription
+
+
+
+ {filtered.slice(0, 12).map((p) => (
+ setProductId(p.id)}
+ />
+ ))}
+
+
+ Selected: {selected.name} · {selected.unit}
+
+
+
+
+
+ Frequency
+
+
+ {FREQUENCIES.map((f) => (
+ setFrequencyDays(f.days)}
+ />
+ ))}
+
+
+
+ Fulfillment
+
+ {
+ setFulfillment(v);
+ if (v === "delivery" && payment === "pay_at_branch") setPayment("chapa");
+ }}
+ options={[
+ { value: "delivery", label: "Delivery" },
+ { value: "pickup", label: "Pickup" },
+ ]}
+ />
+
+
+ Payment
+
+
+ {(
+ [
+ "chapa",
+ "telebirr",
+ "mpesa",
+ ...(fulfillment === "pickup" ? (["pay_at_branch"] as const) : []),
+ ] as PaymentMethod[]
+ ).map((m) => (
+ setPayment(m)}
+ />
+ ))}
+
+
+
+ For family member (optional)
+
+
+ setMemberId(null)} />
+ {members
+ .filter((m) => m.status === "accepted")
+ .map((m) => (
+ setMemberId(m.id)}
+ />
+ ))}
+
+
+ {
+ add({
+ productId: selected.id,
+ productName: selected.name,
+ quantity: Math.max(1, Number(qty) || 1),
+ frequencyDays,
+ fulfillment,
+ paymentMethod: payment,
+ memberId,
+ });
+ setShowCreate(false);
+ Alert.alert(
+ "Subscription active",
+ `${selected.name} every ${frequencyDays} days via ${fulfillment}.`
+ );
+ }}
+ />
+ setShowCreate(false)} />
+
+
+ )}
+
+ {items.map((s) => (
+
+
+
+ {s.productName}
+
+ Every {s.frequencyDays} days · Qty {s.quantity} · {s.fulfillment}
+
+
+ Next: {new Date(s.nextFulfillmentAt).toLocaleDateString()} · {s.paymentMethod}
+ {s.memberId
+ ? ` · ${members.find((m) => m.id === s.memberId)?.name ?? "Family"}`
+ : ""}
+
+
+
+
+
+ {s.status === "active" ? (
+ pause(s.id)} />
+ ) : s.status === "paused" ? (
+ resume(s.id)} />
+ ) : null}
+ {s.status !== "cancelled" ? (
+ cancel(s.id)}
+ />
+ ) : null}
+
+
+ ))}
+
+
+ );
+}
diff --git a/app/(root)/(screens)/tracking/[id].tsx b/app/(root)/(screens)/tracking/[id].tsx
new file mode 100644
index 0000000..33ead38
--- /dev/null
+++ b/app/(root)/(screens)/tracking/[id].tsx
@@ -0,0 +1,122 @@
+import { useLocalSearchParams, router } from "expo-router";
+import { useEffect } from "react";
+import { View } from "react-native";
+import MapView, { Marker } from "@/components/maps/AppMap";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card, InfoRow } from "@/components/ui/Card";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { getBranchById } from "@/lib/data/branches";
+import { routes } from "@/lib/routes";
+import { useOrdersStore } from "@/lib/stores/ordersStore";
+import { colors, gutter } from "@/lib/theme";
+import { formatETB } from "@/lib/utils";
+
+export default function TrackingScreen() {
+ const { id } = useLocalSearchParams<{ id: string }>();
+ const order = useOrdersStore((s) => s.orders.find((o) => o.id === id));
+ const updateStatus = useOrdersStore((s) => s.updateStatus);
+ const branch = order?.branchId ? getBranchById(order.branchId) : undefined;
+
+ useEffect(() => {
+ if (!order) return;
+ if (order.fulfillment === "pickup") return;
+ if (order.riderAssigned || order.status === "cancelled" || order.status === "delivered") {
+ return;
+ }
+ if (order.status === "paid" || order.status === "confirmed") {
+ const t = setTimeout(() => updateStatus(order.id, "dispatched"), 2500);
+ return () => clearTimeout(t);
+ }
+ }, [order?.id, order?.status, order?.fulfillment]);
+
+ if (!order) {
+ return (
+
+
+
+
+ Order not found.
+
+
+
+ );
+ }
+
+ const lat = branch?.lat ?? 9.03;
+ const lng = branch?.lng ?? 38.74;
+ const isPickup = order.fulfillment === "pickup";
+
+ return (
+
+ }
+ />
+
+
+ {!isPickup && order.riderAssigned ? (
+
+ ) : null}
+
+
+
+
+
+ {isPickup
+ ? order.status === "delivered" || order.status === "completed"
+ ? "Collected"
+ : "Ready for pickup soon"
+ : order.riderAssigned
+ ? "Rider on the way"
+ : "Preparing your order"}
+
+
+ {isPickup
+ ? `${branch?.name ?? "Branch"} · ${branch?.hours ?? ""} · ${branch?.area ?? order.areaLabel}`
+ : `${order.areaLabel ?? "Addis Ababa"} · ETA 25–40 min (mock)`}
+
+
+
+
+
+ router.push(routes.orderDetail(order.id))}
+ />
+ {!isPickup && order.status !== "delivered" && order.status !== "cancelled" ? (
+ updateStatus(order.id, "delivered")}
+ />
+ ) : null}
+ {isPickup && order.status !== "delivered" && order.status !== "cancelled" ? (
+ updateStatus(order.id, "delivered")}
+ />
+ ) : null}
+
+
+ );
+}
diff --git a/app/(root)/(tabs)/_layout.tsx b/app/(root)/(tabs)/_layout.tsx
new file mode 100644
index 0000000..a1dc594
--- /dev/null
+++ b/app/(root)/(tabs)/_layout.tsx
@@ -0,0 +1,5 @@
+import { FloatingTabBar } from "@/components/ui/FloatingTabBar";
+
+export default function TabsLayout() {
+ return ;
+}
diff --git a/app/(root)/(tabs)/cart.tsx b/app/(root)/(tabs)/cart.tsx
new file mode 100644
index 0000000..c1d2309
--- /dev/null
+++ b/app/(root)/(tabs)/cart.tsx
@@ -0,0 +1,183 @@
+import { Ionicons } from "@expo/vector-icons";
+import { router } from "expo-router";
+import {
+ Alert,
+ Image,
+ Pressable,
+ ScrollView,
+ TextInput,
+ View,
+} from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { useTranslation } from "react-i18next";
+import { Button } from "@/components/ui/Button";
+import { Card, InfoRow } from "@/components/ui/Card";
+import { EmptyState } from "@/components/ui/EmptyState";
+import { QtyStepper } from "@/components/ui/QtyStepper";
+import { Screen, TAB_BAR_INSET } from "@/components/ui/Screen";
+import { StickyBar } from "@/components/ui/StickyBar";
+import { Text } from "@/components/ui/Text";
+import { DELIVERY_FEE, DEMO_VOUCHER, voucherDiscount } from "@/lib/commerce";
+import { routes } from "@/lib/routes";
+import { useCartStore } from "@/lib/stores/cartStore";
+import { colors, fonts, gutter, radii } from "@/lib/theme";
+import { formatETB } from "@/lib/utils";
+
+export default function CartScreen() {
+ const { t } = useTranslation();
+ const insets = useSafeAreaInsets();
+ const items = useCartStore((s) => s.items);
+ const setQuantity = useCartStore((s) => s.setQuantity);
+ const removeItem = useCartStore((s) => s.removeItem);
+ const subtotal = useCartStore((s) => s.subtotal());
+ const voucher = useCartStore((s) => s.voucherCode);
+ const setVoucher = useCartStore((s) => s.setVoucher);
+ const delivery = items.length ? DELIVERY_FEE : 0;
+ const discount = voucherDiscount(subtotal, voucher);
+ const total = subtotal + delivery - discount;
+
+ return (
+
+
+ {t("common.cart")}
+
+ {items.length} item{items.length === 1 ? "" : "s"} in your bag
+
+
+ {items.length === 0 ? (
+ router.push(routes.shop)}
+ />
+ ) : (
+
+ {items.map((item) => (
+
+
+
+
+
+
+ {item.name}
+
+ removeItem(item.productId)} hitSlop={8}>
+
+
+
+
+ {item.unit}
+ {item.requiresPrescription ? " · RX" : ""}
+
+
+ {formatETB(item.price)}
+ setQuantity(item.productId, n)}
+ min={0}
+ />
+
+
+
+
+ ))}
+
+ router.push(routes.shop)}>
+
+ + Add product
+
+
+
+
+
+ Voucher
+
+
+ setVoucher(v || null)}
+ placeholder="Try GISHEN10"
+ placeholderTextColor={colors.subtle}
+ style={{
+ flex: 1,
+ fontFamily: fonts.regular,
+ fontSize: 14,
+ color: colors.ink,
+ }}
+ />
+ {
+ if ((voucher ?? "").toUpperCase() === DEMO_VOUCHER) {
+ setVoucher(DEMO_VOUCHER);
+ Alert.alert("Applied", "10% off your basket.");
+ } else {
+ Alert.alert("Invalid code", `Use ${DEMO_VOUCHER} for a demo discount.`);
+ }
+ }}
+ />
+
+
+
+
+
+
+ {discount > 0 ? (
+
+ ) : null}
+
+
+
+ )}
+
+
+ {items.length > 0 ? (
+
+ router.push(routes.checkout)}
+ />
+
+ ) : null}
+
+ );
+}
diff --git a/app/(root)/(tabs)/favorites.tsx b/app/(root)/(tabs)/favorites.tsx
new file mode 100644
index 0000000..66403da
--- /dev/null
+++ b/app/(root)/(tabs)/favorites.tsx
@@ -0,0 +1,61 @@
+import { router } from "expo-router";
+import { FlatList, useWindowDimensions, View } from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { useTranslation } from "react-i18next";
+import { EmptyState } from "@/components/ui/EmptyState";
+import { ProductCard, GRID_CARD_GAP } from "@/components/ui/ProductCard";
+import { Screen, TAB_BAR_INSET } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { products } from "@/lib/data/products";
+import { routes } from "@/lib/routes";
+import { useFavoritesStore } from "@/lib/stores/favoritesStore";
+import { gutter } from "@/lib/theme";
+
+export default function FavoritesScreen() {
+ const { t } = useTranslation();
+ const insets = useSafeAreaInsets();
+ const ids = useFavoritesStore((s) => s.ids);
+ const items = products.filter((p) => ids.includes(p.id));
+ const { width } = useWindowDimensions();
+ const cardWidth = (width - gutter * 2 - GRID_CARD_GAP) / 2;
+
+ return (
+
+
+ {t("common.favorites")}
+
+ Saved products for quick reorder
+
+
+ {items.length === 0 ? (
+ router.push(routes.shop)}
+ />
+ ) : (
+ i.id}
+ columnWrapperStyle={{ gap: GRID_CARD_GAP }}
+ contentContainerStyle={{
+ paddingHorizontal: gutter,
+ paddingTop: 12,
+ paddingBottom: TAB_BAR_INSET + 24,
+ gap: GRID_CARD_GAP,
+ }}
+ renderItem={({ item }) => }
+ />
+ )}
+
+ );
+}
diff --git a/app/(root)/(tabs)/index.tsx b/app/(root)/(tabs)/index.tsx
new file mode 100644
index 0000000..1c445b2
--- /dev/null
+++ b/app/(root)/(tabs)/index.tsx
@@ -0,0 +1,247 @@
+import { Ionicons } from "@expo/vector-icons";
+import { router } from "expo-router";
+import { useMemo, useState } from "react";
+import { FlatList, Pressable, ScrollView, View } from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { useTranslation } from "react-i18next";
+import { Avatar } from "@/components/ui/Avatar";
+import { Badge } from "@/components/ui/Badge";
+import { ActionTile, CategoryTile } from "@/components/ui/CategoryTile";
+import { Card, Section } from "@/components/ui/Card";
+import { ProductRow, ProductTile } from "@/components/ui/ProductCard";
+import { Screen, TAB_BAR_INSET } from "@/components/ui/Screen";
+import { SearchAction, SearchField } from "@/components/ui/SearchField";
+import { Text } from "@/components/ui/Text";
+import { products } from "@/lib/data/products";
+import { categories, routes } from "@/lib/routes";
+import { useAuthStore } from "@/lib/stores/authStore";
+import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
+import { colors, gutter, space } from "@/lib/theme";
+
+export default function HomeScreen() {
+ const { t } = useTranslation();
+ const insets = useSafeAreaInsets();
+ const user = useAuthStore((s) => s.user);
+ const [category, setCategory] = useState("medicines");
+ const prescriptions = usePrescriptionStore((s) => s.prescriptions);
+
+ const filtered = useMemo(
+ () => products.filter((p) => p.category === category),
+ [category]
+ );
+
+ const popular = useMemo(
+ () =>
+ [...products]
+ .filter((p) => p.badge === "bestseller" || p.rating >= 4.6)
+ .slice(0, 6),
+ []
+ );
+
+ const refillSoon = prescriptions.find((p) => {
+ if (!p.lastFilledAt || !p.daysSupply) return false;
+ const due = new Date(p.lastFilledAt);
+ due.setDate(due.getDate() + p.daysSupply);
+ const days = (due.getTime() - Date.now()) / (1000 * 60 * 60 * 24);
+ return days <= 5;
+ });
+
+ const pendingRx = prescriptions.find(
+ (p) => p.status === "under_review" || p.status === "submitted"
+ );
+
+ return (
+
+
+
+ router.push(routes.profile)}
+ style={{ flexDirection: "row", alignItems: "center", gap: 12 }}
+ >
+
+
+
+ Good day
+
+ {user?.name?.split(" ")[0] || "Guest"}
+
+
+ router.push(routes.orders)}
+ style={{
+ width: 44,
+ height: 44,
+ borderRadius: 22,
+ backgroundColor: colors.surface,
+ borderWidth: 1,
+ borderColor: colors.line,
+ alignItems: "center",
+ justifyContent: "center",
+ }}
+ >
+
+
+
+
+
+ {t("common.trustedTitle")}
+
+
+ {t("common.trustedSubtitle")}
+
+
+
+ router.push(routes.search)}
+ trailing={
+ router.push(routes.rxScan)}
+ />
+ }
+ />
+
+
+ {(refillSoon || pendingRx) && (
+ router.push(routes.rxList)}
+ style={{ marginTop: 14 }}
+ >
+
+
+
+
+
+
+
+ {refillSoon
+ ? `${t("common.refillDue")}: ${refillSoon.medicineName}`
+ : `Rx under review: ${pendingRx?.medicineName}`}
+
+
+ Tap to manage prescriptions
+
+
+
+
+
+
+ )}
+
+
+ router.push(routes.rxScan)}
+ />
+ router.push(routes.rxScan)}
+ />
+
+
+ router.push(routes.shop)}>
+
+ {categories.map((c) => (
+
+ setCategory(c.id)}
+ />
+
+ ))}
+
+
+
+ router.push(routes.shop)}>
+ p.badge === "sale" || p.compareAt).slice(0, 8)}
+ keyExtractor={(item) => item.id}
+ showsHorizontalScrollIndicator={false}
+ ItemSeparatorComponent={() => }
+ renderItem={({ item }) => }
+ ListEmptyComponent={
+ item.id}
+ showsHorizontalScrollIndicator={false}
+ ItemSeparatorComponent={() => }
+ renderItem={({ item }) => }
+ />
+ }
+ />
+
+
+ router.push(routes.shop)}>
+
+ {popular.map((p) => (
+
+ ))}
+
+
+
+ router.push(routes.rxList)}>
+
+ {prescriptions.slice(0, 2).map((rx) => (
+ router.push(routes.rxDetail(rx.id))}
+ >
+
+
+ {rx.medicineName}
+
+ {rx.patientName} · {rx.daysSupply} day supply
+
+
+
+
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/app/(root)/(tabs)/profile.tsx b/app/(root)/(tabs)/profile.tsx
new file mode 100644
index 0000000..550334b
--- /dev/null
+++ b/app/(root)/(tabs)/profile.tsx
@@ -0,0 +1,307 @@
+import { Ionicons } from "@expo/vector-icons";
+import * as ImagePicker from "expo-image-picker";
+import { router } from "expo-router";
+import { useState } from "react";
+import { Alert, Linking, Pressable, ScrollView, View } from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { useTranslation } from "react-i18next";
+import { Avatar } from "@/components/ui/Avatar";
+import { Badge } from "@/components/ui/Badge";
+import { Button } from "@/components/ui/Button";
+import { Card, MenuRow } from "@/components/ui/Card";
+import { Field } from "@/components/ui/Field";
+import { Screen, TAB_BAR_INSET } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { routes } from "@/lib/routes";
+import { useAuthStore } from "@/lib/stores/authStore";
+import { useLangStore } from "@/lib/stores/langStore";
+import { useProfileModeStore } from "@/lib/stores/profileModeStore";
+import { colors, gutter } from "@/lib/theme";
+import { CALL_PHONE, CHATWOOT_BASE, WHATSAPP_NUMBER } from "@/lib/utils";
+
+export default function ProfileScreen() {
+ const { t } = useTranslation();
+ const insets = useSafeAreaInsets();
+ const user = useAuthStore((s) => s.user);
+ const setAvatar = useAuthStore((s) => s.setAvatar);
+ const updateProfile = useAuthStore((s) => s.updateProfile);
+ const signOut = useAuthStore((s) => s.signOut);
+ const setHasOnboarded = useAuthStore((s) => s.setHasOnboarded);
+ const mode = useProfileModeStore((s) => s.mode);
+ const membership = useProfileModeStore((s) => s.activeMembership());
+ const language = useLangStore((s) => s.language);
+ const setLanguage = useLangStore((s) => s.setLanguage);
+
+ const [editing, setEditing] = useState(false);
+ const [name, setName] = useState(user?.name ?? "");
+ const [phone, setPhone] = useState(user?.phone ?? "");
+ const [email, setEmail] = useState(user?.email ?? "");
+
+ const pickAvatar = async () => {
+ const permission = await ImagePicker.requestMediaLibraryPermissionsAsync();
+ if (!permission.granted) {
+ Alert.alert(
+ "Photo access needed",
+ "Allow photo library access to set your profile picture."
+ );
+ return;
+ }
+
+ const result = await ImagePicker.launchImageLibraryAsync({
+ mediaTypes: ["images"],
+ allowsEditing: true,
+ aspect: [1, 1],
+ quality: 0.85,
+ });
+
+ if (!result.canceled && result.assets[0]?.uri) {
+ setAvatar(result.assets[0].uri);
+ }
+ };
+
+ const takePhoto = async () => {
+ const permission = await ImagePicker.requestCameraPermissionsAsync();
+ if (!permission.granted) {
+ Alert.alert("Camera access needed", "Allow camera access to take a profile photo.");
+ return;
+ }
+ const result = await ImagePicker.launchCameraAsync({
+ allowsEditing: true,
+ aspect: [1, 1],
+ quality: 0.85,
+ });
+ if (!result.canceled && result.assets[0]?.uri) {
+ setAvatar(result.assets[0].uri);
+ }
+ };
+
+ const changePhoto = () => {
+ Alert.alert("Profile photo", "Choose how you'd like to update your photo.", [
+ { text: "Choose from library", onPress: pickAvatar },
+ { text: "Take photo", onPress: takePhoto },
+ ...(user?.avatarUri
+ ? [{ text: "Remove photo", style: "destructive" as const, onPress: () => setAvatar(null) }]
+ : []),
+ { text: "Cancel", style: "cancel" },
+ ]);
+ };
+
+ const links: {
+ label: string;
+ href: string;
+ icon: keyof typeof Ionicons.glyphMap;
+ subtitle?: string;
+ }[] = [
+ { label: t("common.switchProfile"), href: routes.profileSwitch, icon: "swap-horizontal", subtitle: mode },
+ { label: t("common.joinOrg"), href: routes.profileJoin, icon: "business-outline" },
+ { label: t("common.orders"), href: routes.orders, icon: "receipt-outline", subtitle: "Track delivery" },
+ { label: t("common.prescriptions"), href: routes.rxList, icon: "document-text-outline" },
+ { label: t("common.loyalty"), href: routes.loyalty, icon: "star-outline", subtitle: `${user?.points ?? 0} pts` },
+ { label: t("common.family"), href: routes.family, icon: "people-outline" },
+ { label: t("common.subscriptions"), href: routes.subscriptions, icon: "repeat-outline" },
+ { label: t("common.emergencyContacts"), href: routes.emergencyContacts, icon: "alert-circle-outline" },
+ { label: t("common.branches"), href: routes.branches, icon: "location-outline" },
+ { label: t("common.addresses"), href: routes.addresses, icon: "home-outline" },
+ { label: t("common.language"), href: routes.language, icon: "language-outline", subtitle: language.toUpperCase() },
+ { label: t("common.about"), href: routes.about, icon: "information-circle-outline" },
+ { label: t("common.contact"), href: routes.contact, icon: "mail-outline" },
+ ];
+
+ return (
+
+
+ {t("common.profile")}
+
+
+
+
+
+
+
+
+
+
+
+
+ {user?.name || "Guest"}
+
+ {user?.phone || "—"}
+
+ {user?.email ? (
+
+ {user.email}
+
+ ) : null}
+
+
+
+
+
+
+
+
+
+ {user?.avatarUri ? "Change photo" : "Add photo"}
+
+
+ {!user?.isGuest ? (
+ {
+ setName(user?.name ?? "");
+ setPhone(user?.phone ?? "");
+ setEmail(user?.email ?? "");
+ setEditing((v) => !v);
+ }}
+ >
+
+ {editing ? "Close editor" : "Edit profile"}
+
+
+ ) : null}
+
+ {membership ? (
+
+ {membership.planName} · {membership.remainingAllowance} ETB allowance left
+
+ ) : null}
+
+
+ {editing && !user?.isGuest ? (
+
+
+ Edit profile
+
+
+
+
+
+ {
+ if (!name.trim()) {
+ Alert.alert("Name required");
+ return;
+ }
+ updateProfile({
+ name: name.trim(),
+ phone: phone.trim(),
+ email: email.trim() || undefined,
+ });
+ setEditing(false);
+ Alert.alert("Saved", "Your profile was updated.");
+ }}
+ />
+
+
+ ) : null}
+
+
+ {[
+ { label: t("common.call"), icon: "call-outline" as const, href: `tel:${CALL_PHONE}` },
+ {
+ label: t("common.whatsapp"),
+ icon: "logo-whatsapp" as const,
+ href: `https://wa.me/${WHATSAPP_NUMBER}`,
+ },
+ { label: t("common.chat"), icon: "chatbubble-ellipses-outline" as const, href: CHATWOOT_BASE },
+ ].map((item) => (
+ Linking.openURL(item.href)}
+ style={{
+ flex: 1,
+ backgroundColor: colors.surface,
+ borderRadius: 16,
+ borderWidth: 1,
+ borderColor: colors.line,
+ paddingVertical: 12,
+ alignItems: "center",
+ gap: 4,
+ }}
+ >
+
+ {item.label}
+
+ ))}
+
+
+
+ setLanguage(language === "en" ? "am" : "en")}
+ right={
+
+ {language.toUpperCase()}
+
+ }
+ />
+ {links.map((l, index) => (
+ router.push(l.href as never)}
+ last={index === links.length - 1}
+ />
+ ))}
+
+
+
+ {
+ signOut();
+ setHasOnboarded(false);
+ router.replace(routes.welcome);
+ }}
+ />
+
+
+
+ );
+}
diff --git a/app/(root)/_layout.tsx b/app/(root)/_layout.tsx
new file mode 100644
index 0000000..e23ad18
--- /dev/null
+++ b/app/(root)/_layout.tsx
@@ -0,0 +1,13 @@
+import { Stack } from "expo-router";
+import { colors } from "@/lib/theme";
+
+export default function RootGroupLayout() {
+ return (
+
+ );
+}
diff --git a/app/(root)/auth/_layout.tsx b/app/(root)/auth/_layout.tsx
new file mode 100644
index 0000000..5b9eb40
--- /dev/null
+++ b/app/(root)/auth/_layout.tsx
@@ -0,0 +1,5 @@
+import { Stack } from "expo-router";
+
+export default function AuthLayout() {
+ return ;
+}
diff --git a/app/(root)/auth/language.tsx b/app/(root)/auth/language.tsx
new file mode 100644
index 0000000..2e81cf7
--- /dev/null
+++ b/app/(root)/auth/language.tsx
@@ -0,0 +1,58 @@
+import { router } from "expo-router";
+import { useTranslation } from "react-i18next";
+import { Pressable, View } from "react-native";
+import { Button } from "@/components/ui/Button";
+import { AppHeader } from "@/components/ui/Header";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { routes } from "@/lib/routes";
+import { useLangStore, type Language } from "@/lib/stores/langStore";
+import { colors, gutter } from "@/lib/theme";
+
+const OPTIONS: { code: Language; label: string; hint: string }[] = [
+ { code: "en", label: "English", hint: "Continue in English" },
+ { code: "am", label: "አማርኛ", hint: "በአማርኛ ይቀጥሉ" },
+];
+
+export default function LanguageScreen() {
+ const { t } = useTranslation();
+ const language = useLangStore((s) => s.language);
+ const setLanguage = useLangStore((s) => s.setLanguage);
+
+ return (
+
+
+
+
+ {OPTIONS.map((opt) => {
+ const selected = language === opt.code;
+ return (
+ setLanguage(opt.code)}
+ style={{
+ padding: 18,
+ borderRadius: 20,
+ backgroundColor: colors.surface,
+ borderWidth: selected ? 2 : 1,
+ borderColor: selected ? colors.brand : colors.line,
+ }}
+ >
+ {opt.label}
+
+ {opt.hint}
+
+
+ );
+ })}
+
+
+ router.push(routes.otp)}
+ style={{ marginBottom: 16 }}
+ />
+
+
+ );
+}
diff --git a/app/(root)/auth/otp.tsx b/app/(root)/auth/otp.tsx
new file mode 100644
index 0000000..4e917b7
--- /dev/null
+++ b/app/(root)/auth/otp.tsx
@@ -0,0 +1,135 @@
+import { useState } from "react";
+import { Alert, View } from "react-native";
+import { router } from "expo-router";
+import * as LocalAuthentication from "expo-local-authentication";
+import { useTranslation } from "react-i18next";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { Button } from "@/components/ui/Button";
+import { Field, SwitchRow } from "@/components/ui/Field";
+import { Card } from "@/components/ui/Card";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { DEMO_OTP } from "@/lib/commerce";
+import { colors, gutter } from "@/lib/theme";
+import { routes } from "@/lib/routes";
+import { useAuthStore } from "@/lib/stores/authStore";
+
+export default function OtpScreen() {
+ const { t } = useTranslation();
+ const insets = useSafeAreaInsets();
+ const signIn = useAuthStore((s) => s.signIn);
+ const setHasOnboarded = useAuthStore((s) => s.setHasOnboarded);
+ const setBiometric = useAuthStore((s) => s.setBiometric);
+ const [phone, setPhone] = useState("+251911000000");
+ const [name, setName] = useState("Kirukib Abebe");
+ const [email, setEmail] = useState("kirukib@example.com");
+ const [code, setCode] = useState("");
+ const [sent, setSent] = useState(false);
+ const [bio, setBio] = useState(false);
+
+ const sendCode = () => {
+ if (!name.trim() || phone.replace(/\D/g, "").length < 9) {
+ Alert.alert("Missing info", "Enter your name and a valid phone number.");
+ return;
+ }
+ setSent(true);
+ Alert.alert(
+ "Code sent (demo)",
+ `Use OTP ${DEMO_OTP} to verify. No real SMS is sent in this build.`
+ );
+ };
+
+ const verify = async () => {
+ if (!sent) return;
+ if (code.trim() !== DEMO_OTP) {
+ Alert.alert("Invalid OTP", `Enter the demo code ${DEMO_OTP}.`);
+ return;
+ }
+ if (bio) {
+ const hw = await LocalAuthentication.hasHardwareAsync();
+ if (hw) {
+ const res = await LocalAuthentication.authenticateAsync({
+ promptMessage: "Enable biometric unlock",
+ });
+ if (!res.success) {
+ Alert.alert("Biometric", "Skipped — you can enable later in profile.");
+ }
+ }
+ }
+ signIn({
+ name: name.trim(),
+ phone: phone.trim(),
+ email: email.trim() || undefined,
+ isGuest: false,
+ });
+ setBiometric(bio);
+ setHasOnboarded(true);
+ router.replace(routes.home);
+ };
+
+ return (
+
+
+ {t("common.signIn")}
+
+ {t("common.otpHint")} Demo OTP is always {DEMO_OTP}.
+
+
+
+
+
+ {sent ? (
+
+ ) : null}
+
+
+
+
+
+ {!sent ? (
+
+ ) : (
+
+
+
+
+ )}
+
+
+ );
+}
diff --git a/app/(root)/auth/welcome.tsx b/app/(root)/auth/welcome.tsx
new file mode 100644
index 0000000..4e042d7
--- /dev/null
+++ b/app/(root)/auth/welcome.tsx
@@ -0,0 +1,71 @@
+import { Image, View } from "react-native";
+import { router } from "expo-router";
+import { useTranslation } from "react-i18next";
+import { Button } from "@/components/ui/Button";
+import { Screen } from "@/components/ui/Screen";
+import { Text } from "@/components/ui/Text";
+import { brand } from "@/lib/data/brand";
+import { colors, gutter } from "@/lib/theme";
+import { routes } from "@/lib/routes";
+import { useAuthStore } from "@/lib/stores/authStore";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+
+export default function WelcomeScreen() {
+ const { t } = useTranslation();
+ const insets = useSafeAreaInsets();
+ const setHasOnboarded = useAuthStore((s) => s.setHasOnboarded);
+
+ return (
+
+
+
+
+
+ {t("common.appName")}
+
+
+ {t("common.tagline")}
+
+
+ Est. {brand.founded} · {brand.branchCount} branches · Serving {brand.institutions}+
+ institutions across Addis Ababa.
+
+
+
+ router.push(routes.language)} />
+ {
+ useAuthStore.getState().signIn({
+ name: "Guest",
+ phone: "",
+ isGuest: true,
+ });
+ setHasOnboarded(true);
+ router.replace(routes.home);
+ }}
+ />
+
+ Guests can browse. Loyalty, corporate and some care features need a signed-in account.
+
+
+
+
+ );
+}
diff --git a/app/_layout.tsx b/app/_layout.tsx
new file mode 100644
index 0000000..8e81d4b
--- /dev/null
+++ b/app/_layout.tsx
@@ -0,0 +1,49 @@
+import "./global.css";
+import "@/lib/i18n";
+import { useEffect } from "react";
+import { Stack } from "expo-router";
+import { StatusBar } from "expo-status-bar";
+import { useFonts } from "expo-font";
+import * as SplashScreen from "expo-splash-screen";
+import { GestureHandlerRootView } from "react-native-gesture-handler";
+import { SafeAreaProvider } from "react-native-safe-area-context";
+import { PlusJakartaSans_400Regular } from "@expo-google-fonts/plus-jakarta-sans/400Regular";
+import { PlusJakartaSans_500Medium } from "@expo-google-fonts/plus-jakarta-sans/500Medium";
+import { PlusJakartaSans_600SemiBold } from "@expo-google-fonts/plus-jakarta-sans/600SemiBold";
+import { PlusJakartaSans_700Bold } from "@expo-google-fonts/plus-jakarta-sans/700Bold";
+import { PlusJakartaSans_800ExtraBold } from "@expo-google-fonts/plus-jakarta-sans/800ExtraBold";
+import { colors } from "@/lib/theme";
+
+SplashScreen.preventAutoHideAsync().catch(() => {});
+
+export default function RootLayout() {
+ const [fontsLoaded, fontError] = useFonts({
+ Jakarta_400Regular: PlusJakartaSans_400Regular,
+ Jakarta_500Medium: PlusJakartaSans_500Medium,
+ Jakarta_600SemiBold: PlusJakartaSans_600SemiBold,
+ Jakarta_700Bold: PlusJakartaSans_700Bold,
+ Jakarta_800ExtraBold: PlusJakartaSans_800ExtraBold,
+ });
+
+ const ready = fontsLoaded || !!fontError;
+
+ useEffect(() => {
+ if (ready) SplashScreen.hideAsync().catch(() => {});
+ }, [ready]);
+
+ if (!ready) return null;
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/app/global.css b/app/global.css
new file mode 100644
index 0000000..b5c61c9
--- /dev/null
+++ b/app/global.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/app/index.tsx b/app/index.tsx
new file mode 100644
index 0000000..f89aaa3
--- /dev/null
+++ b/app/index.tsx
@@ -0,0 +1,10 @@
+import { Redirect } from "expo-router";
+import { useAuthStore } from "@/lib/stores/authStore";
+
+export default function Index() {
+ const hasOnboarded = useAuthStore((s) => s.hasOnboarded);
+ if (!hasOnboarded) {
+ return ;
+ }
+ return ;
+}
diff --git a/assets/adaptive-icon.png b/assets/adaptive-icon.png
new file mode 100644
index 0000000..9fa4870
Binary files /dev/null and b/assets/adaptive-icon.png differ
diff --git a/assets/icon.png b/assets/icon.png
new file mode 100644
index 0000000..9fa4870
Binary files /dev/null and b/assets/icon.png differ
diff --git a/assets/logo/gishen-logo.png b/assets/logo/gishen-logo.png
new file mode 100644
index 0000000..0c99d0d
Binary files /dev/null and b/assets/logo/gishen-logo.png differ
diff --git a/assets/splash-icon.png b/assets/splash-icon.png
new file mode 100644
index 0000000..9fa4870
Binary files /dev/null and b/assets/splash-icon.png differ
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 0000000..f99f037
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,16 @@
+module.exports = function (api) {
+ api.cache(true);
+ return {
+ presets: [
+ [
+ "babel-preset-expo",
+ {
+ jsxImportSource: "nativewind",
+ // Zustand ESM uses import.meta; required for Expo web (SDK 53).
+ unstable_transformImportMeta: true,
+ },
+ ],
+ "nativewind/babel",
+ ],
+ };
+};
diff --git a/components/maps/AppMap.tsx b/components/maps/AppMap.tsx
new file mode 100644
index 0000000..8172064
--- /dev/null
+++ b/components/maps/AppMap.tsx
@@ -0,0 +1,2 @@
+export { default } from "react-native-maps";
+export { Marker } from "react-native-maps";
diff --git a/components/maps/AppMap.web.tsx b/components/maps/AppMap.web.tsx
new file mode 100644
index 0000000..e13c6c6
--- /dev/null
+++ b/components/maps/AppMap.web.tsx
@@ -0,0 +1,62 @@
+import type { ReactNode } from "react";
+import { StyleSheet, Text, View, type StyleProp, type ViewStyle } from "react-native";
+import { colors } from "@/lib/theme";
+
+type Region = {
+ latitude: number;
+ longitude: number;
+ latitudeDelta: number;
+ longitudeDelta: number;
+};
+
+type MapProps = {
+ style?: StyleProp;
+ initialRegion?: Region;
+ children?: ReactNode;
+};
+
+export default function MapView({ style, children }: MapProps) {
+ return (
+
+ Map preview
+ Live maps are available on iOS and Android.
+ {children}
+
+ );
+}
+
+type MarkerProps = {
+ coordinate: { latitude: number; longitude: number };
+ title?: string;
+ description?: string;
+ pinColor?: string;
+};
+
+export function Marker({ title, description }: MarkerProps) {
+ return (
+
+ {title ?? "Pin"}
+ {description ? {description} : null}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ wrap: {
+ backgroundColor: "#E8EDF2",
+ alignItems: "center",
+ justifyContent: "center",
+ gap: 8,
+ padding: 24,
+ },
+ title: { fontSize: 16, fontWeight: "800", color: colors.ink },
+ sub: { fontSize: 13, color: colors.muted, textAlign: "center" },
+ marker: {
+ marginTop: 12,
+ paddingHorizontal: 12,
+ paddingVertical: 8,
+ backgroundColor: "#fff",
+ borderRadius: 8,
+ },
+ markerTitle: { fontWeight: "700", color: colors.ink },
+});
diff --git a/components/ui/Avatar.tsx b/components/ui/Avatar.tsx
new file mode 100644
index 0000000..9a14b31
--- /dev/null
+++ b/components/ui/Avatar.tsx
@@ -0,0 +1,60 @@
+import { Image, View } from "react-native";
+import { Text } from "@/components/ui/Text";
+import { colors } from "@/lib/theme";
+
+function initials(name?: string) {
+ if (!name) return "G";
+ return name
+ .trim()
+ .split(/\s+/)
+ .slice(0, 2)
+ .map((part) => part[0]?.toUpperCase() ?? "")
+ .join("");
+}
+
+export function Avatar({
+ name,
+ uri,
+ size = 44,
+ tone = "brand",
+}: {
+ name?: string;
+ uri?: string | null;
+ size?: number;
+ tone?: "brand" | "soft";
+}) {
+ if (uri) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+ {initials(name)}
+
+
+ );
+}
diff --git a/components/ui/Badge.tsx b/components/ui/Badge.tsx
new file mode 100644
index 0000000..ff74da1
--- /dev/null
+++ b/components/ui/Badge.tsx
@@ -0,0 +1,138 @@
+import { Ionicons } from "@expo/vector-icons";
+import { View, type StyleProp, type ViewStyle } from "react-native";
+import { Text } from "@/components/ui/Text";
+import { colors, radii } from "@/lib/theme";
+
+type Tone = "brand" | "danger" | "warn" | "info" | "neutral" | "dark";
+
+const tones: Record = {
+ brand: { bg: colors.brandSoft, fg: colors.brandText },
+ danger: { bg: colors.dangerSoft, fg: colors.danger },
+ warn: { bg: colors.warnSoft, fg: colors.warn },
+ info: { bg: colors.infoSoft, fg: colors.info },
+ neutral: { bg: colors.surfaceAlt, fg: colors.muted },
+ dark: { bg: colors.ink, fg: colors.surface },
+};
+
+export function Badge({
+ label,
+ tone = "brand",
+ icon,
+ solid,
+ style,
+}: {
+ label: string;
+ tone?: Tone;
+ icon?: keyof typeof Ionicons.glyphMap;
+ /** Filled lime treatment used for discount flags on imagery. */
+ solid?: boolean;
+ style?: StyleProp;
+}) {
+ const skin = tones[tone];
+ const bg = solid ? colors.brand : skin.bg;
+ const fg = solid ? colors.ink : skin.fg;
+
+ return (
+
+ {icon ? : null}
+
+ {label}
+
+
+ );
+}
+
+export function StockLabel({
+ inStock,
+ count,
+}: {
+ inStock: boolean;
+ count?: number;
+}) {
+ return (
+
+ {inStock ? `In stock${count ? ` (${count})` : ""}` : "Out of stock"}
+
+ );
+}
+
+export function Rating({
+ value,
+ count,
+ showStars = true,
+ size = 13,
+}: {
+ value: number;
+ count?: number;
+ showStars?: boolean;
+ size?: number;
+}) {
+ return (
+
+ {showStars ? (
+
+ {[1, 2, 3, 4, 5].map((i) => (
+ = i ? "star" : value >= i - 0.5 ? "star-half" : "star-outline"
+ }
+ size={size}
+ color={value >= i - 0.5 ? colors.star : colors.disabled}
+ />
+ ))}
+
+ ) : (
+
+ )}
+
+ {value.toFixed(1)}
+ {count !== undefined ? ` (${count})` : ""}
+
+
+ );
+}
+
+/** Compact price with optional struck-through original. */
+export function Price({
+ value,
+ compareAt,
+ size = "md",
+ format,
+}: {
+ value: number;
+ compareAt?: number;
+ size?: "sm" | "md" | "lg";
+ format: (n: number) => string;
+}) {
+ return (
+
+
+ {format(value)}
+
+ {compareAt && compareAt > value ? (
+
+ {format(compareAt)}
+
+ ) : null}
+
+ );
+}
diff --git a/components/ui/Button.tsx b/components/ui/Button.tsx
new file mode 100644
index 0000000..22a0a8b
--- /dev/null
+++ b/components/ui/Button.tsx
@@ -0,0 +1,200 @@
+import type { ReactNode } from "react";
+import { Ionicons } from "@expo/vector-icons";
+import {
+ ActivityIndicator,
+ Pressable,
+ View,
+ type PressableProps,
+ type StyleProp,
+ type ViewStyle,
+} from "react-native";
+import { Text } from "@/components/ui/Text";
+import { colors, radii, shadows } from "@/lib/theme";
+
+type Variant = "primary" | "brand" | "dark" | "outline" | "ghost" | "soft" | "danger";
+type Size = "sm" | "md" | "lg";
+
+type Props = Omit & {
+ title: string;
+ variant?: Variant;
+ size?: Size;
+ icon?: keyof typeof Ionicons.glyphMap;
+ iconRight?: keyof typeof Ionicons.glyphMap;
+ loading?: boolean;
+ fullWidth?: boolean;
+ elevated?: boolean;
+ style?: StyleProp;
+};
+
+const skins: Record = {
+ // Lime fill with ink text: on-brand and far more legible than white-on-lime.
+ primary: { bg: colors.brand, fg: colors.ink, border: "transparent" },
+ brand: { bg: colors.brand, fg: colors.ink, border: "transparent" },
+ dark: { bg: colors.ink, fg: colors.surface, border: "transparent" },
+ outline: { bg: "transparent", fg: colors.ink, border: colors.line },
+ ghost: { bg: "transparent", fg: colors.ink, border: "transparent" },
+ soft: { bg: colors.brandSoft, fg: colors.brandText, border: "transparent" },
+ danger: { bg: colors.dangerSoft, fg: colors.danger, border: "transparent" },
+};
+
+const sizing: Record = {
+ sm: { py: 9, px: 14, gap: 6, icon: 15 },
+ md: { py: 13, px: 18, gap: 8, icon: 17 },
+ lg: { py: 16, px: 22, gap: 9, icon: 19 },
+};
+
+export function Button({
+ title,
+ variant = "primary",
+ size = "lg",
+ icon,
+ iconRight,
+ loading,
+ disabled,
+ fullWidth = true,
+ elevated,
+ style,
+ ...rest
+}: Props) {
+ const skin = skins[variant];
+ const dims = sizing[size];
+ const inactive = disabled || loading;
+
+ return (
+ [
+ {
+ backgroundColor: inactive ? colors.surfaceAlt : skin.bg,
+ borderColor: skin.border,
+ borderWidth: variant === "outline" ? 1.5 : 0,
+ borderRadius: radii.pill,
+ paddingVertical: dims.py,
+ paddingHorizontal: dims.px,
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "center",
+ gap: dims.gap,
+ alignSelf: fullWidth ? "stretch" : "flex-start",
+ opacity: pressed ? 0.88 : 1,
+ transform: [{ scale: pressed ? 0.99 : 1 }],
+ },
+ elevated && !inactive && shadows.sm,
+ style,
+ ]}
+ {...rest}
+ >
+ {loading ? (
+
+ ) : (
+ <>
+ {icon ? (
+
+ ) : null}
+
+ {title}
+
+ {iconRight ? (
+
+ ) : null}
+ >
+ )}
+
+ );
+}
+
+/** Circular icon button used in headers and cards. */
+export function IconButton({
+ icon,
+ onPress,
+ size = 40,
+ tone = "surface",
+ color,
+ accessibilityLabel,
+}: {
+ icon: keyof typeof Ionicons.glyphMap;
+ onPress?: () => void;
+ size?: number;
+ tone?: "surface" | "brand" | "dark" | "plain";
+ color?: string;
+ accessibilityLabel?: string;
+}) {
+ const bg =
+ tone === "brand"
+ ? colors.brand
+ : tone === "dark"
+ ? colors.ink
+ : tone === "plain"
+ ? "transparent"
+ : colors.surface;
+ const fg = color ?? (tone === "dark" ? colors.surface : colors.ink);
+
+ return (
+ [
+ {
+ width: size,
+ height: size,
+ borderRadius: size / 2,
+ backgroundColor: bg,
+ alignItems: "center",
+ justifyContent: "center",
+ opacity: pressed ? 0.7 : 1,
+ },
+ tone === "surface" && { borderWidth: 1, borderColor: colors.line },
+ ]}
+ >
+
+
+ );
+}
+
+/** Small round "+" affordance on product cards. */
+export function AddButton({
+ onPress,
+ disabled,
+ size = 34,
+}: {
+ onPress?: () => void;
+ disabled?: boolean;
+ size?: number;
+}) {
+ return (
+ ({
+ width: size,
+ height: size,
+ borderRadius: size / 2,
+ backgroundColor: disabled ? colors.surfaceAlt : colors.brand,
+ alignItems: "center",
+ justifyContent: "center",
+ opacity: pressed ? 0.8 : 1,
+ })}
+ >
+
+
+ );
+}
+
+export function ButtonRow({ children }: { children: ReactNode }) {
+ return {children};
+}
diff --git a/components/ui/Card.tsx b/components/ui/Card.tsx
new file mode 100644
index 0000000..bcccc42
--- /dev/null
+++ b/components/ui/Card.tsx
@@ -0,0 +1,221 @@
+import type { ReactNode } from "react";
+import {
+ Pressable,
+ View,
+ type StyleProp,
+ type ViewStyle,
+} from "react-native";
+import { Ionicons } from "@expo/vector-icons";
+import { Text } from "@/components/ui/Text";
+import { colors, radii, shadows, space } from "@/lib/theme";
+
+export function Card({
+ children,
+ onPress,
+ padded = true,
+ tone = "surface",
+ elevated = true,
+ style,
+}: {
+ children: ReactNode;
+ onPress?: () => void;
+ padded?: boolean;
+ tone?: "surface" | "wash" | "brand";
+ elevated?: boolean;
+ style?: StyleProp;
+}) {
+ const bg =
+ tone === "wash" ? colors.surfaceAlt : tone === "brand" ? colors.brandWash : colors.surface;
+
+ const base: StyleProp = [
+ {
+ backgroundColor: bg,
+ borderRadius: radii.card,
+ borderWidth: 1,
+ borderColor: tone === "brand" ? colors.brandBorder : colors.line,
+ padding: padded ? space.lg : 0,
+ overflow: "hidden",
+ },
+ elevated && tone === "surface" ? shadows.xs : null,
+ style,
+ ];
+
+ if (!onPress) return {children};
+
+ return (
+ [base, pressed && { opacity: 0.92 }]}
+ >
+ {children}
+
+ );
+}
+
+export function SectionHeader({
+ title,
+ action,
+ onAction,
+ style,
+}: {
+ title: string;
+ action?: string;
+ onAction?: () => void;
+ style?: StyleProp;
+}) {
+ return (
+
+ {title}
+ {action ? (
+
+
+ {action}
+
+
+ ) : null}
+
+ );
+}
+
+export function Section({
+ title,
+ action,
+ onAction,
+ children,
+ style,
+}: {
+ title?: string;
+ action?: string;
+ onAction?: () => void;
+ children: ReactNode;
+ style?: StyleProp;
+}) {
+ return (
+
+ {title ? : null}
+ {children}
+
+ );
+}
+
+export function Divider({ style }: { style?: StyleProp }) {
+ return ;
+}
+
+/** Key/value row used for drug facts and order summaries. */
+export function InfoRow({
+ label,
+ value,
+ valueColor,
+ emphasis,
+ last,
+}: {
+ label: string;
+ value: string;
+ valueColor?: string;
+ emphasis?: boolean;
+ last?: boolean;
+}) {
+ return (
+
+
+ {label}
+
+
+ {value}
+
+
+ );
+}
+
+/** Tappable settings/menu row with icon tile, title and chevron. */
+export function MenuRow({
+ icon,
+ title,
+ subtitle,
+ onPress,
+ right,
+ tone = "brand",
+ last,
+}: {
+ icon: keyof typeof Ionicons.glyphMap;
+ title: string;
+ subtitle?: string;
+ onPress?: () => void;
+ right?: ReactNode;
+ tone?: "brand" | "danger" | "neutral";
+ last?: boolean;
+}) {
+ const iconBg =
+ tone === "danger"
+ ? colors.dangerSoft
+ : tone === "neutral"
+ ? colors.surfaceAlt
+ : colors.brandSoft;
+ const iconFg =
+ tone === "danger" ? colors.danger : tone === "neutral" ? colors.muted : colors.brandText;
+
+ return (
+ ({
+ flexDirection: "row",
+ alignItems: "center",
+ gap: 14,
+ paddingVertical: 14,
+ paddingHorizontal: space.lg,
+ borderBottomWidth: last ? 0 : 1,
+ borderBottomColor: colors.line,
+ backgroundColor: pressed ? colors.surfaceAlt : "transparent",
+ })}
+ >
+
+
+
+
+
+ {title}
+
+ {subtitle ? (
+
+ {subtitle}
+
+ ) : null}
+
+ {right ?? }
+
+ );
+}
diff --git a/components/ui/CategoryTile.tsx b/components/ui/CategoryTile.tsx
new file mode 100644
index 0000000..8607acf
--- /dev/null
+++ b/components/ui/CategoryTile.tsx
@@ -0,0 +1,109 @@
+import { Ionicons } from "@expo/vector-icons";
+import { Pressable, View } from "react-native";
+import { Text } from "@/components/ui/Text";
+import { colors, radii } from "@/lib/theme";
+
+export function CategoryTile({
+ icon,
+ label,
+ selected,
+ onPress,
+}: {
+ icon: keyof typeof Ionicons.glyphMap;
+ label: string;
+ selected?: boolean;
+ onPress?: () => void;
+}) {
+ return (
+ ({
+ width: 72,
+ alignItems: "center",
+ gap: 7,
+ opacity: pressed ? 0.85 : 1,
+ })}
+ >
+
+
+
+
+ {label}
+
+
+ );
+}
+
+/** Larger square action used for the prescription entry points on Home. */
+export function ActionTile({
+ icon,
+ title,
+ subtitle,
+ tone = "brand",
+ onPress,
+}: {
+ icon: keyof typeof Ionicons.glyphMap;
+ title: string;
+ subtitle: string;
+ tone?: "brand" | "surface";
+ onPress?: () => void;
+}) {
+ const brand = tone === "brand";
+
+ return (
+ ({
+ flex: 1,
+ backgroundColor: brand ? colors.brand : colors.surface,
+ borderRadius: radii.card,
+ borderWidth: 1,
+ borderColor: brand ? colors.brand : colors.line,
+ padding: 14,
+ gap: 10,
+ opacity: pressed ? 0.92 : 1,
+ })}
+ >
+
+
+
+
+
+ {title}
+
+
+ {subtitle}
+
+
+
+ );
+}
diff --git a/components/ui/Chip.tsx b/components/ui/Chip.tsx
new file mode 100644
index 0000000..b31f647
--- /dev/null
+++ b/components/ui/Chip.tsx
@@ -0,0 +1,138 @@
+import type { ReactNode } from "react";
+import { Ionicons } from "@expo/vector-icons";
+import { Pressable, ScrollView, View } from "react-native";
+import { Text } from "@/components/ui/Text";
+import { colors, radii, space } from "@/lib/theme";
+
+export function Chip({
+ label,
+ selected,
+ onPress,
+ onRemove,
+ icon,
+ tone = "default",
+ size = "md",
+}: {
+ label: string;
+ selected?: boolean;
+ onPress?: () => void;
+ onRemove?: () => void;
+ icon?: keyof typeof Ionicons.glyphMap;
+ tone?: "default" | "outline";
+ size?: "sm" | "md";
+}) {
+ const bg = selected ? colors.brand : tone === "outline" ? "transparent" : colors.surface;
+ const fg = selected ? colors.ink : colors.muted;
+ const border = selected ? colors.brand : colors.line;
+
+ return (
+ ({
+ flexDirection: "row",
+ alignItems: "center",
+ gap: 6,
+ paddingVertical: size === "sm" ? 6 : 9,
+ paddingHorizontal: size === "sm" ? 10 : 14,
+ borderRadius: radii.pill,
+ backgroundColor: bg,
+ borderWidth: 1,
+ borderColor: border,
+ opacity: pressed ? 0.8 : 1,
+ })}
+ >
+ {icon ? : null}
+
+ {label}
+
+ {onRemove ? (
+
+
+
+ ) : null}
+
+ );
+}
+
+/** Horizontally scrolling chip strip that bleeds to the screen edge. */
+export function ChipRow({
+ children,
+ gutters = 20,
+}: {
+ children: ReactNode;
+ gutters?: number;
+}) {
+ return (
+
+ {children}
+
+ );
+}
+
+/** Read-only meta tag, e.g. "Tablet" or "Qty: 100". */
+export function MetaTag({
+ label,
+ icon,
+}: {
+ label: string;
+ icon?: keyof typeof Ionicons.glyphMap;
+}) {
+ return (
+
+ {icon ? : null}
+
+ {label}
+
+
+ );
+}
+
+export function Segmented({
+ options,
+ value,
+ onChange,
+}: {
+ options: { value: T; label: string }[];
+ value: T;
+ onChange: (value: T) => void;
+}) {
+ return (
+
+ {options.map((option) => {
+ const active = option.value === value;
+ return (
+ onChange(option.value)}
+ style={{
+ flex: 1,
+ alignItems: "center",
+ paddingVertical: 10,
+ borderRadius: radii.pill,
+ backgroundColor: active ? colors.surface : "transparent",
+ }}
+ >
+
+ {option.label}
+
+
+ );
+ })}
+
+ );
+}
diff --git a/components/ui/EmptyState.tsx b/components/ui/EmptyState.tsx
new file mode 100644
index 0000000..793c07a
--- /dev/null
+++ b/components/ui/EmptyState.tsx
@@ -0,0 +1,61 @@
+import { Ionicons } from "@expo/vector-icons";
+import { View } from "react-native";
+import { Button } from "@/components/ui/Button";
+import { Text } from "@/components/ui/Text";
+import { colors } from "@/lib/theme";
+
+export function EmptyState({
+ icon = "cube-outline",
+ title,
+ body,
+ actionTitle,
+ onAction,
+ compact,
+}: {
+ icon?: keyof typeof Ionicons.glyphMap;
+ title: string;
+ body?: string;
+ actionTitle?: string;
+ onAction?: () => void;
+ compact?: boolean;
+}) {
+ return (
+
+
+
+
+
+ {title}
+
+ {body ? (
+
+ {body}
+
+ ) : null}
+ {actionTitle && onAction ? (
+
+ ) : null}
+
+ );
+}
diff --git a/components/ui/Field.tsx b/components/ui/Field.tsx
new file mode 100644
index 0000000..e80e03a
--- /dev/null
+++ b/components/ui/Field.tsx
@@ -0,0 +1,232 @@
+import { useState, type ReactNode } from "react";
+import { Ionicons } from "@expo/vector-icons";
+import {
+ Pressable,
+ Switch,
+ TextInput,
+ View,
+ type TextInputProps,
+} from "react-native";
+import { Text } from "@/components/ui/Text";
+import { colors, fonts, radii } from "@/lib/theme";
+
+type FieldProps = TextInputProps & {
+ label?: string;
+ icon?: keyof typeof Ionicons.glyphMap;
+ error?: string;
+ hint?: string;
+ secure?: boolean;
+};
+
+export function Field({
+ label,
+ icon,
+ error,
+ hint,
+ secure,
+ style,
+ ...rest
+}: FieldProps) {
+ const [focused, setFocused] = useState(false);
+ const [hidden, setHidden] = useState(!!secure);
+
+ const borderColor = error ? colors.danger : focused ? colors.brand : colors.line;
+
+ return (
+
+ {label ? (
+
+ {label}
+
+ ) : null}
+
+ {icon ? (
+
+ ) : null}
+ setFocused(true)}
+ onBlur={() => setFocused(false)}
+ style={[
+ {
+ flex: 1,
+ fontFamily: fonts.regular,
+ fontSize: 14,
+ color: colors.ink,
+ paddingVertical: 0,
+ },
+ style,
+ ]}
+ {...rest}
+ />
+ {secure ? (
+ setHidden(!hidden)} hitSlop={8}>
+
+
+ ) : null}
+
+ {error ? (
+
+
+
+ {error}
+
+
+ ) : hint ? (
+
+ {hint}
+
+ ) : null}
+
+ );
+}
+
+export function SwitchRow({
+ title,
+ subtitle,
+ value,
+ onValueChange,
+ icon,
+ last,
+}: {
+ title: string;
+ subtitle?: string;
+ value: boolean;
+ onValueChange: (v: boolean) => void;
+ icon?: keyof typeof Ionicons.glyphMap;
+ last?: boolean;
+}) {
+ return (
+
+ {icon ? (
+
+
+
+ ) : null}
+
+ {title}
+ {subtitle ? (
+
+ {subtitle}
+
+ ) : null}
+
+
+
+ );
+}
+
+/** Radio-style selectable row used for payment methods and addresses. */
+export function OptionRow({
+ title,
+ subtitle,
+ selected,
+ onPress,
+ icon,
+ trailing,
+ last,
+}: {
+ title: string;
+ subtitle?: string;
+ selected: boolean;
+ onPress: () => void;
+ icon?: keyof typeof Ionicons.glyphMap;
+ trailing?: ReactNode;
+ last?: boolean;
+}) {
+ return (
+
+ {icon ? (
+
+
+
+ ) : null}
+
+ {title}
+ {subtitle ? (
+
+ {subtitle}
+
+ ) : null}
+
+ {trailing}
+
+
+ );
+}
diff --git a/components/ui/FloatingTabBar.tsx b/components/ui/FloatingTabBar.tsx
new file mode 100644
index 0000000..bc5fe5e
--- /dev/null
+++ b/components/ui/FloatingTabBar.tsx
@@ -0,0 +1,140 @@
+import { Ionicons } from "@expo/vector-icons";
+import { Tabs } from "expo-router";
+import { View } from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { useTranslation } from "react-i18next";
+import { Text } from "@/components/ui/Text";
+import { colors, fonts, radii, shadows } from "@/lib/theme";
+import { useCartStore } from "@/lib/stores/cartStore";
+
+function TabIcon({
+ name,
+ focused,
+ badge,
+}: {
+ name: keyof typeof Ionicons.glyphMap;
+ focused: boolean;
+ badge?: number;
+}) {
+ return (
+
+
+
+
+ {badge ? (
+
+
+ {badge > 9 ? "9+" : badge}
+
+
+ ) : null}
+
+ );
+}
+
+export function FloatingTabBar() {
+ const insets = useSafeAreaInsets();
+ const { t } = useTranslation();
+ const cartCount = useCartStore((s) => s.totalItems());
+
+ return (
+
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+
+ );
+}
diff --git a/components/ui/Header.tsx b/components/ui/Header.tsx
new file mode 100644
index 0000000..30285e9
--- /dev/null
+++ b/components/ui/Header.tsx
@@ -0,0 +1,76 @@
+import type { ReactNode } from "react";
+import { router } from "expo-router";
+import { View } from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { IconButton } from "@/components/ui/Button";
+import { Text } from "@/components/ui/Text";
+import { colors, gutter } from "@/lib/theme";
+
+type Props = {
+ title?: string;
+ subtitle?: string;
+ /** Large left-aligned title, matching the "Explore Products" reference. */
+ large?: boolean;
+ back?: boolean;
+ onBack?: () => void;
+ right?: ReactNode;
+ background?: string;
+};
+
+export function AppHeader({
+ title,
+ subtitle,
+ large,
+ back = true,
+ onBack,
+ right,
+ background = "transparent",
+}: Props) {
+ const insets = useSafeAreaInsets();
+
+ return (
+
+
+ {back ? (
+ router.back())}
+ />
+ ) : null}
+ {!large && title ? (
+
+ {title}
+
+ ) : (
+
+ )}
+ {right}
+
+
+ {large && title ? (
+
+ {title}
+ {subtitle ? (
+
+ {subtitle}
+
+ ) : null}
+
+ ) : null}
+
+ {!large && subtitle ? (
+
+ {subtitle}
+
+ ) : null}
+
+ );
+}
diff --git a/components/ui/ProductCard.tsx b/components/ui/ProductCard.tsx
new file mode 100644
index 0000000..cb93aaf
--- /dev/null
+++ b/components/ui/ProductCard.tsx
@@ -0,0 +1,262 @@
+import { Ionicons } from "@expo/vector-icons";
+import { router } from "expo-router";
+import { Image, Pressable, View } from "react-native";
+import { AddButton } from "@/components/ui/Button";
+import { Badge, Price, StockLabel } from "@/components/ui/Badge";
+import { MetaTag } from "@/components/ui/Chip";
+import { Text } from "@/components/ui/Text";
+import { getDrugFacts } from "@/lib/data/clinical";
+import type { Product } from "@/lib/data/products";
+import { routes } from "@/lib/routes";
+import { useCartStore } from "@/lib/stores/cartStore";
+import { useFavoritesStore } from "@/lib/stores/favoritesStore";
+import { colors, radii, shadows, space } from "@/lib/theme";
+import { formatETB } from "@/lib/utils";
+
+export const GRID_CARD_GAP = 12;
+
+function discount(product: Product) {
+ if (!product.compareAt || product.compareAt <= product.price) return null;
+ return `${Math.round(((product.compareAt - product.price) / product.compareAt) * 100)}% OFF`;
+}
+
+function useCardActions(product: Product) {
+ const addProduct = useCartStore((s) => s.addProduct);
+ return {
+ open: () => router.push(routes.product(product.id)),
+ add: () => addProduct(product, 1),
+ };
+}
+
+/** Grid tile used in shop, search results and category listings. */
+export function ProductCard({
+ product,
+ width,
+}: {
+ product: Product;
+ width?: number | `${number}%`;
+}) {
+ const { open, add } = useCardActions(product);
+ const facts = getDrugFacts(product);
+ const off = discount(product);
+
+ return (
+ [
+ {
+ width,
+ backgroundColor: colors.surface,
+ borderRadius: radii.card,
+ borderWidth: 1,
+ borderColor: colors.line,
+ padding: space.md,
+ opacity: pressed ? 0.94 : 1,
+ },
+ shadows.xs,
+ ]}
+ >
+
+
+ {off ? (
+
+ ) : null}
+ {product.requiresPrescription ? (
+
+ ) : null}
+
+
+
+ {facts.useCase}
+
+
+ {product.name}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+/** Horizontal row used in "Most popular", favorites and list-view results. */
+export function ProductRow({ product }: { product: Product }) {
+ const { open, add } = useCardActions(product);
+ const facts = getDrugFacts(product);
+
+ return (
+ [
+ {
+ flexDirection: "row",
+ gap: space.md,
+ backgroundColor: colors.surface,
+ borderRadius: radii.card,
+ borderWidth: 1,
+ borderColor: colors.line,
+ padding: space.md,
+ alignItems: "center",
+ opacity: pressed ? 0.94 : 1,
+ },
+ shadows.xs,
+ ]}
+ >
+
+
+
+
+
+
+ {facts.useCase}
+
+
+ {product.name}
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+/** Compact tile for horizontal carousels on the home screen. */
+export function ProductTile({ product }: { product: Product }) {
+ const { open, add } = useCardActions(product);
+ const liked = useFavoritesStore((s) => s.has(product.id));
+ const toggle = useFavoritesStore((s) => s.toggle);
+ const off = discount(product);
+
+ return (
+ [
+ {
+ width: 158,
+ backgroundColor: colors.surface,
+ borderRadius: radii.card,
+ borderWidth: 1,
+ borderColor: colors.line,
+ padding: space.md,
+ opacity: pressed ? 0.94 : 1,
+ },
+ shadows.xs,
+ ]}
+ >
+
+
+ {off ? (
+
+ ) : null}
+ toggle(product.id)}
+ hitSlop={8}
+ style={{
+ position: "absolute",
+ top: 6,
+ right: 6,
+ width: 26,
+ height: 26,
+ borderRadius: 13,
+ backgroundColor: colors.surface,
+ alignItems: "center",
+ justifyContent: "center",
+ }}
+ >
+
+
+
+
+
+ {product.name}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/components/ui/QtyStepper.tsx b/components/ui/QtyStepper.tsx
new file mode 100644
index 0000000..333d13b
--- /dev/null
+++ b/components/ui/QtyStepper.tsx
@@ -0,0 +1,83 @@
+import { Ionicons } from "@expo/vector-icons";
+import { Pressable, View } from "react-native";
+import { Text } from "@/components/ui/Text";
+import { colors, radii } from "@/lib/theme";
+
+export function QtyStepper({
+ value,
+ onChange,
+ min = 1,
+ max = 99,
+ size = "md",
+}: {
+ value: number;
+ onChange: (n: number) => void;
+ min?: number;
+ max?: number;
+ size?: "sm" | "md";
+}) {
+ const dim = size === "sm" ? 26 : 32;
+ const iconSize = size === "sm" ? 14 : 17;
+
+ const step = (delta: number) => {
+ const next = Math.min(max, Math.max(min, value + delta));
+ if (next !== value) onChange(next);
+ };
+
+ return (
+
+ step(-1)}
+ disabled={value <= min}
+ style={{
+ width: dim,
+ height: dim,
+ borderRadius: dim / 2,
+ alignItems: "center",
+ justifyContent: "center",
+ backgroundColor: colors.surfaceAlt,
+ }}
+ >
+
+
+
+ {value}
+
+ step(1)}
+ disabled={value >= max}
+ style={{
+ width: dim,
+ height: dim,
+ borderRadius: dim / 2,
+ alignItems: "center",
+ justifyContent: "center",
+ backgroundColor: value >= max ? colors.surfaceAlt : colors.brand,
+ }}
+ >
+ = max ? colors.disabled : colors.ink}
+ />
+
+
+ );
+}
diff --git a/components/ui/Screen.tsx b/components/ui/Screen.tsx
new file mode 100644
index 0000000..30e716d
--- /dev/null
+++ b/components/ui/Screen.tsx
@@ -0,0 +1,63 @@
+import type { ReactNode } from "react";
+import {
+ ScrollView,
+ View,
+ type ScrollViewProps,
+ type StyleProp,
+ type ViewStyle,
+} from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { colors, gutter } from "@/lib/theme";
+
+type ScreenProps = {
+ children: ReactNode;
+ /** Adds bottom room for the floating tab bar. */
+ tabBarPadding?: boolean;
+ background?: string;
+ style?: StyleProp;
+};
+
+export function Screen({ children, background = colors.page, style }: ScreenProps) {
+ return {children};
+}
+
+type ScreenScrollProps = ScrollViewProps & {
+ children: ReactNode;
+ /** Extra bottom inset, e.g. for a sticky bar or the floating tab bar. */
+ bottomInset?: number;
+ /** Set false when the screen renders its own header with the top inset. */
+ topInset?: boolean;
+ gutters?: boolean;
+};
+
+export function ScreenScroll({
+ children,
+ bottomInset = 32,
+ topInset = false,
+ gutters = true,
+ contentContainerStyle,
+ ...rest
+}: ScreenScrollProps) {
+ const insets = useSafeAreaInsets();
+
+ return (
+
+ {children}
+
+ );
+}
+
+/** Bottom padding that clears the floating tab bar. */
+export const TAB_BAR_INSET = 96;
diff --git a/components/ui/SearchField.tsx b/components/ui/SearchField.tsx
new file mode 100644
index 0000000..308a4ab
--- /dev/null
+++ b/components/ui/SearchField.tsx
@@ -0,0 +1,119 @@
+import { useState, type ReactNode } from "react";
+import { Ionicons } from "@expo/vector-icons";
+import {
+ Pressable,
+ TextInput,
+ View,
+ type TextInputProps,
+} from "react-native";
+import { Text } from "@/components/ui/Text";
+import { colors, fonts, radii } from "@/lib/theme";
+
+type Props = TextInputProps & {
+ onClear?: () => void;
+ /** Renders as a button instead of an input (home screen → search screen). */
+ readOnlyPress?: () => void;
+ trailing?: ReactNode;
+};
+
+export function SearchField({
+ value,
+ onClear,
+ readOnlyPress,
+ trailing,
+ placeholder = "Search medicine, brand or symptom",
+ ...rest
+}: Props) {
+ const [focused, setFocused] = useState(false);
+
+ const body = (
+
+
+ {readOnlyPress ? (
+
+ {value || placeholder}
+
+ ) : (
+ setFocused(true)}
+ onBlur={() => setFocused(false)}
+ returnKeyType="search"
+ style={{
+ flex: 1,
+ fontFamily: fonts.regular,
+ fontSize: 14,
+ color: colors.ink,
+ paddingVertical: 0,
+ }}
+ {...rest}
+ />
+ )}
+ {value && onClear && !readOnlyPress ? (
+
+
+
+ ) : null}
+ {trailing}
+
+ );
+
+ if (readOnlyPress) {
+ return (
+ ({ opacity: pressed ? 0.9 : 1 })}>
+ {body}
+
+ );
+ }
+
+ return body;
+}
+
+/** Lime pill action that sits inside the search field (scan entry point). */
+export function SearchAction({
+ icon,
+ label,
+ onPress,
+}: {
+ icon: keyof typeof Ionicons.glyphMap;
+ label?: string;
+ onPress?: () => void;
+}) {
+ return (
+ ({
+ flexDirection: "row",
+ alignItems: "center",
+ gap: 6,
+ backgroundColor: colors.brand,
+ borderRadius: radii.pill,
+ paddingHorizontal: label ? 14 : 10,
+ height: 40,
+ opacity: pressed ? 0.85 : 1,
+ })}
+ >
+
+ {label ? (
+
+ {label}
+
+ ) : null}
+
+ );
+}
diff --git a/components/ui/StickyBar.tsx b/components/ui/StickyBar.tsx
new file mode 100644
index 0000000..714d1a4
--- /dev/null
+++ b/components/ui/StickyBar.tsx
@@ -0,0 +1,62 @@
+import type { ReactNode } from "react";
+import { View } from "react-native";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
+import { colors, gutter, radii, shadows } from "@/lib/theme";
+
+/**
+ * Bottom action bar. `floating` renders the dark pill used on product detail;
+ * the default renders a flush surface bar used in cart and checkout.
+ */
+export function StickyBar({
+ children,
+ floating,
+}: {
+ children: ReactNode;
+ floating?: boolean;
+}) {
+ const insets = useSafeAreaInsets();
+
+ if (floating) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/components/ui/Text.tsx b/components/ui/Text.tsx
new file mode 100644
index 0000000..01540c6
--- /dev/null
+++ b/components/ui/Text.tsx
@@ -0,0 +1,27 @@
+import { Text as RNText, type TextProps as RNTextProps } from "react-native";
+import { colors, typography, type TypeVariant } from "@/lib/theme";
+
+export type TextProps = RNTextProps & {
+ variant?: TypeVariant;
+ color?: string;
+ center?: boolean;
+};
+
+/**
+ * App-wide text primitive. React Native does not inherit `fontFamily`, so every
+ * piece of copy goes through here to stay on the type scale.
+ */
+export function Text({
+ variant = "body",
+ color = colors.ink,
+ center,
+ style,
+ ...rest
+}: TextProps) {
+ return (
+
+ );
+}
diff --git a/docs/BACKEND_SPEC.md b/docs/BACKEND_SPEC.md
new file mode 100644
index 0000000..20ac13e
--- /dev/null
+++ b/docs/BACKEND_SPEC.md
@@ -0,0 +1,135 @@
+# Gishen-Mob Backend Spec
+
+**Base URL (TBD):** `https://api.gishen.example/v1`
+**Auth:** Bearer JWT after phone OTP
+**Headers:** `Authorization`, `Accept-Language` (`en` | `am`), `Content-Type: application/json`
+
+Shared with Gishen-Ecom / Gishen-B2B where noted.
+Patch this file whenever a feature is added or finalized.
+
+## Auth
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| POST | `/auth/otp/request` | Required | `{ phone }` |
+| POST | `/auth/otp/verify` | Required | `{ phone, code }` → session + user |
+| POST | `/auth/biometric/bind` | Required | Device biometric public key |
+| GET | `/users/me` | Required | Profile, locale, points, tier |
+| PATCH | `/users/me` | Required | name, email, `locale`, biometric flag |
+
+## Locale
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| PATCH | `/users/me` | Required | `{ locale: "en" \| "am" }` |
+| — | Accept-Language | Required | All requests |
+
+## Catalog
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| GET | `/catalog/products` | Required | q, category, badge, max — parity with Ecom |
+| GET | `/catalog/products/:idOrSlug` | Required | |
+| GET | `/catalog/categories` | Required | |
+
+## Branches / Stock
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| GET | `/branches` | Required | |
+| GET | `/branches/nearby` | Required | `lat`, `lng` |
+| GET | `/stock/product/:productId` | Required | Nearby availability |
+
+## Orders
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| POST | `/orders` | Required | items, fulfillment, branchId?, location, paymentMethod, prescriptionFileKeys?, notes, credit? |
+| GET | `/orders/me` | Required | |
+| GET | `/orders/:id` | Required | |
+| GET | `/orders/:id/tracking` | Required | Rider trail when assigned |
+| POST | `/orders/:id/cancel` | Required | |
+
+## Payments
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| POST | `/payments/initiate` | Required | `chapa` \| `telebirr` \| `mpesa` only for delivery |
+| POST | `/payments/webhook/*` | Required | Gateway callbacks |
+| — | `pay_at_branch` | Required | Allowed **only** when `fulfillment=pickup` |
+
+## Prescriptions
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| POST | `/uploads/signed-url` | Required | Rx images |
+| POST | `/prescriptions` | Required | Multi-page keys, medicines[], patient, memberId? |
+| POST | `/prescriptions/check` | Required | Match catalog → ready/review/unavailable |
+| GET | `/prescriptions/me` | Required | |
+| POST | `/prescriptions/:id/reorder` | Required | |
+
+## Reminders
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| POST | `/health/reminders` | Required | Dose/refill schedules |
+| POST | `/health/reminders/:id/confirm` | Required | `dose.confirmed` |
+| GET | `/health/reminders/me` | Required | |
+
+## Emergency contacts
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| GET | `/users/me/emergency-contacts` | Required | |
+| POST | `/users/me/emergency-contacts` | Required | name, phone, relationship |
+| DELETE | `/users/me/emergency-contacts/:id` | Required | |
+| — | Job `dose.missed_escalation` | Required | After grace (default 30m) SMS/push to contact if no confirm |
+
+## Family
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| GET | `/family/members` | Required | |
+| POST | `/family/invites` | Required | phone or link code |
+| POST | `/family/invites/accept` | Required | |
+| DELETE | `/family/members/:id` | Required | |
+
+## Subscriptions
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| GET | `/subscriptions/me` | Required | |
+| POST | `/subscriptions` | Required | |
+| POST | `/subscriptions/:id/pause` | Required | |
+| POST | `/subscriptions/:id/resume` | Required | |
+| POST | `/subscriptions/:id/cancel` | Required | |
+
+## B2B / Corporate (shared with Gishen-B2B)
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| GET | `/users/me/contexts` | Required | personal + org memberships |
+| POST | `/orgs/join` | Required | `{ code }` |
+| GET | `/company/me` | Required | Member view: plan, allowance |
+| POST | `/checkout/credit/quote` | Required | Basket split covered vs selfPay |
+
+## Loyalty
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| GET | `/loyalty/me` | Required | |
+| GET | `/loyalty/me/ledger` | Required | |
+| POST | `/loyalty/redeem` | Required | |
+| GET | `/referrals/me` | Required | |
+
+## Push / Tracking
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| POST | `/devices` | Required | push token |
+| — | Events | Required | order.*, dispatch.*, dose.*, refill.*, escalation.* |
+| GET | `/orders/:id/tracking` | Required | |
+
+## Contact / Support
+| Method | Path | Status | Notes |
+|--------|------|--------|-------|
+| POST | `/contact` | Required | |
+| — | Chatwoot | Deeplink | https://chat.yaltopia.com |
+
+### Changelog
+- 2026-08-06: Scaffold — skeleton created with all domains.
+- 2026-08-06: Auth/Locale — OTP mock, biometric bind flag, language picker en/am, Accept-Language noted.
+- 2026-08-06: Catalog — products/categories from Ecom data port; shop/search/favorites.
+- 2026-08-06: Branches/Stock — GPS nearest sort; pickup selection (stock map stub).
+- 2026-08-06: Orders/Payments/B2B — checkout with Chapa/Telebirr/M-Pesa; pay_at_branch pickup-only; WhatsApp handoff; credit quote split stub.
+- 2026-08-06: Prescriptions/Reminders/Emergency — camera multi-page scan, check statuses, calendar dose push, escalation job contract.
+- 2026-08-06: Family/Subscriptions — invite/manage; refill subscription CRUD.
+- 2026-08-06: B2B/Account — contexts, join codes, profile switcher.
+- 2026-08-06: Loyalty/Push/Tracking — wallet redeem/referral; order tracking map mock; device push channels.
+- 2026-08-06: Contact/Support — contact form + Chatwoot/WhatsApp/call deeplinks.
diff --git a/lib/api/client.ts b/lib/api/client.ts
new file mode 100644
index 0000000..3331f1f
--- /dev/null
+++ b/lib/api/client.ts
@@ -0,0 +1,34 @@
+/** API client stub — swap BASE_URL when shared backend is live. */
+
+export const BASE_URLS = {
+ core: process.env.EXPO_PUBLIC_API_URL ?? "https://api.gishen.example/v1",
+} as const;
+
+export type ApiError = { message: string; code?: string };
+
+export async function callEndpoint(
+ path: string,
+ init?: RequestInit & { locale?: string }
+): Promise {
+ const headers: Record = {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ ...(init?.locale ? { "Accept-Language": init.locale } : {}),
+ ...(init?.headers as Record),
+ };
+
+ // Mock mode until backend exists
+ if (!process.env.EXPO_PUBLIC_API_URL) {
+ throw new Error(`API not configured for ${path}`);
+ }
+
+ const res = await fetch(`${BASE_URLS.core}${path}`, {
+ ...init,
+ headers,
+ });
+ if (!res.ok) {
+ const body = (await res.json().catch(() => ({}))) as ApiError;
+ throw new Error(body.message || res.statusText);
+ }
+ return res.json() as Promise;
+}
diff --git a/lib/commerce.ts b/lib/commerce.ts
new file mode 100644
index 0000000..047964d
--- /dev/null
+++ b/lib/commerce.ts
@@ -0,0 +1,21 @@
+/** Shared commerce numbers so cart, checkout and orders stay consistent. */
+export const DELIVERY_FEE = 80;
+export const DEMO_VOUCHER = "GISHEN10";
+export const DEMO_VOUCHER_PCT = 0.1;
+export const DEMO_OTP = "1234";
+
+export function voucherDiscount(subtotal: number, code: string | null | undefined) {
+ if (!code) return 0;
+ if (code.trim().toUpperCase() === DEMO_VOUCHER) {
+ return Math.round(subtotal * DEMO_VOUCHER_PCT);
+ }
+ return 0;
+}
+
+export function orderSubtotalTotal(input: {
+ subtotal: number;
+ deliveryFee: number;
+ discount?: number;
+}) {
+ return Math.max(0, input.subtotal + input.deliveryFee - (input.discount ?? 0));
+}
diff --git a/lib/data/branches.ts b/lib/data/branches.ts
new file mode 100644
index 0000000..7d9cdf5
--- /dev/null
+++ b/lib/data/branches.ts
@@ -0,0 +1,142 @@
+export type Branch = {
+ id: string;
+ slug: string;
+ name: string;
+ area: string;
+ phone: string;
+ hours: string;
+ is24h: boolean;
+ lat: number;
+ lng: number;
+ pickupAvailable: boolean;
+ mapsUrl: string;
+};
+
+/** Verified from gishenpharmacy.wordpress.com contact page + public listings. */
+export const branches: Branch[] = [
+ {
+ id: "bole",
+ slug: "bole",
+ name: "Bole Branch",
+ area: "Bole, Addis Ababa",
+ phone: "+251930033290",
+ hours: "Open 24 hours",
+ is24h: true,
+ lat: 8.9806,
+ lng: 38.799,
+ pickupAvailable: true,
+ mapsUrl:
+ "https://www.google.com/maps/search/?api=1&query=Gishen%20Pharmacy%20Bole%20Addis%20Ababa",
+ },
+ {
+ id: "cmc",
+ slug: "cmc-michael",
+ name: "CMC Michael Branch",
+ area: "CMC Michael, Addis Ababa",
+ phone: "+251930102175",
+ hours: "Open 24 hours",
+ is24h: true,
+ lat: 9.0227,
+ lng: 38.826,
+ pickupAvailable: true,
+ mapsUrl:
+ "https://www.google.com/maps/search/?api=1&query=Gishen%20Pharmacy%20CMC%20Michael%20Addis%20Ababa",
+ },
+ {
+ id: "jemo",
+ slug: "jemo",
+ name: "Jemo Branch",
+ area: "Jemo, Addis Ababa",
+ phone: "+251930033292",
+ hours: "Open 24 hours",
+ is24h: true,
+ lat: 8.963,
+ lng: 38.72,
+ pickupAvailable: true,
+ mapsUrl:
+ "https://www.google.com/maps/search/?api=1&query=Gishen%20Pharmacy%20Jemo%20Addis%20Ababa",
+ },
+ {
+ id: "stadium",
+ slug: "stadium",
+ name: "Stadium Branch",
+ area: "Stadium, Addis Ababa",
+ phone: "+251930033291",
+ hours: "8:00 AM – 8:00 PM",
+ is24h: false,
+ lat: 9.012,
+ lng: 38.763,
+ pickupAvailable: true,
+ mapsUrl:
+ "https://www.google.com/maps/search/?api=1&query=Gishen%20Pharmacy%20Stadium%20Addis%20Ababa",
+ },
+ {
+ id: "mexico",
+ slug: "mexico",
+ name: "Mexico Branch",
+ area: "Mexico Square, Addis Ababa",
+ phone: "+251935998678",
+ hours: "8:00 AM – 9:00 PM",
+ is24h: false,
+ lat: 9.01,
+ lng: 38.745,
+ pickupAvailable: true,
+ mapsUrl:
+ "https://www.google.com/maps/search/?api=1&query=Gishen%20Pharmacy%20Mexico%20Addis%20Ababa",
+ },
+ {
+ id: "golagol",
+ slug: "golagol",
+ name: "Golagol Branch",
+ area: "Golagol, Addis Ababa",
+ phone: "+251930076930",
+ hours: "8:00 AM – 8:00 PM",
+ is24h: false,
+ lat: 9.03,
+ lng: 38.75,
+ pickupAvailable: true,
+ mapsUrl:
+ "https://www.google.com/maps/search/?api=1&query=Gishen%20Pharmacy%20Golagol%20Addis%20Ababa",
+ },
+ {
+ id: "hayahulet",
+ slug: "hayahulet",
+ name: "Hayahulet Branch",
+ area: "Hayahulet, Addis Ababa",
+ phone: "+251930033292",
+ hours: "8:00 AM – 8:00 PM",
+ is24h: false,
+ lat: 9.02,
+ lng: 38.79,
+ pickupAvailable: true,
+ mapsUrl:
+ "https://www.google.com/maps/search/?api=1&query=Gishen%20Pharmacy%20Hayahulet%20Addis%20Ababa",
+ },
+];
+
+export function getBranchById(id: string) {
+ return branches.find((b) => b.id === id);
+}
+
+export function distanceKm(
+ lat1: number,
+ lng1: number,
+ lat2: number,
+ lng2: number,
+) {
+ const toRad = (v: number) => (v * Math.PI) / 180;
+ const R = 6371;
+ const dLat = toRad(lat2 - lat1);
+ const dLng = toRad(lng2 - lng1);
+ const a =
+ Math.sin(dLat / 2) ** 2 +
+ Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng / 2) ** 2;
+ return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+}
+
+export function nearestBranches(lat: number, lng: number, limit = 3) {
+ return [...branches]
+ .map((b) => ({ ...b, distance: distanceKm(lat, lng, b.lat, b.lng) }))
+ .sort((a, b) => a.distance - b.distance)
+ .slice(0, limit);
+}
diff --git a/lib/data/brand.ts b/lib/data/brand.ts
new file mode 100644
index 0000000..4be5a69
--- /dev/null
+++ b/lib/data/brand.ts
@@ -0,0 +1,38 @@
+export const brand = {
+ name: "Gishen Pharmacy",
+ shortName: "Gishen",
+ tagline: "Healthcare delivered to your doorstep",
+ description:
+ "Established in 1994, Gishen Pharmacy is a trusted pharmaceutical retailer in Ethiopia with multiple branches across Addis Ababa.",
+ phone: "+251930099850",
+ phoneDisplay: "+251 930 099 850",
+ whatsapp: "251930099850",
+ email: "info@gishenpharmacy.org",
+ orderEmail: "orders@gishenpharmacy.org",
+ website: "https://gishenpharmacy.org",
+ founded: 1994,
+ branchCount: 7,
+ weeklyCustomers: 1218,
+ institutions: 146,
+ logo: "/brand/gishen-logo.png",
+ address: "Addis Ababa, Ethiopia",
+ googleRating: 4.4,
+ googleReviewCount: 120,
+ googleMapsUrl:
+ "https://www.google.com/maps/search/?api=1&query=Gishen%20Pharmacy%20Addis%20Ababa",
+ socials: [
+ {
+ id: "whatsapp",
+ label: "WhatsApp",
+ href: "https://wa.me/251930099850",
+ },
+ ] as { id: string; label: string; href: string }[],
+ story:
+ "Established in 1994, Gishen Group (Gishen Pharmacy) is one of the household names in the pharmaceutical retail industry in Ethiopia. The company has grown from a single branch to a multi-branch operation in Addis Ababa, serving individuals and 146+ institutional clients with medicines, medical equipment, cosmetics, baby products, compounding, and consulting.",
+ purpose:
+ "To provide the highest quality products and services that enhance the well-being of humanity — improving access to exceptional healthcare solutions across Ethiopia.",
+ vision:
+ "To enhance accessibility to the finest pharmaceutical products, services, and medical equipment, bridging the gap between supply and demand.",
+ mission:
+ "To instill hope by delivering exceptional quality healthcare solutions through the retailing of pharmaceutical goods and services in Ethiopia.",
+};
diff --git a/lib/data/clinical.ts b/lib/data/clinical.ts
new file mode 100644
index 0000000..e1a2522
--- /dev/null
+++ b/lib/data/clinical.ts
@@ -0,0 +1,322 @@
+import type { Product } from "@/lib/data/products";
+
+export type StorageNote = {
+ icon: "thermometer-outline" | "sunny-outline" | "happy-outline" | "water-outline";
+ title: string;
+ body: string;
+};
+
+export type DrugFacts = {
+ /** Short therapeutic label shown above the product name. */
+ useCase: string;
+ /** Dose form: Tablet, Syrup, Cream, Device… */
+ form: string;
+ genericName: string;
+ brandNames: string;
+ drugClass: string;
+ /** Selectable strengths on the detail page. Empty for non-dosed products. */
+ dosages: string[];
+ sideEffects: { mild: string[]; severe: string[] };
+ storage: StorageNote[];
+ directions: { title: string; body: string }[];
+ stockCount: number;
+ /** Pharmacist guidance shown in the safety callout. */
+ advice: string;
+};
+
+const CATEGORY_USE_CASE: Record = {
+ medicines: "General Medicine",
+ vitamins: "Supplements",
+ "personal-care": "Personal Care",
+ diabetic: "Diabetes Care",
+ devices: "Medical Device",
+ baby: "Baby Care",
+ "first-aid": "First Aid",
+ wellness: "Sexual Wellness",
+};
+
+const CATEGORY_FORM: Record = {
+ medicines: "Tablet",
+ vitamins: "Tablet",
+ "personal-care": "Topical",
+ diabetic: "Tablet",
+ devices: "Device",
+ baby: "Topical",
+ "first-aid": "Supply",
+ wellness: "Tablet",
+};
+
+/** Per-product clinical overrides. Everything else falls back to category defaults. */
+const OVERRIDES: Record> = {
+ "panadol-advance": {
+ useCase: "Pain & Fever",
+ genericName: "Paracetamol (Acetaminophen)",
+ brandNames: "Panadol, Tylenol, Calpol",
+ drugClass: "Analgesic / Antipyretic",
+ dosages: ["500mg", "650mg"],
+ sideEffects: {
+ mild: ["Nausea", "Sleepiness", "Stomach upset"],
+ severe: ["Liver damage", "Rash", "Breathing issues"],
+ },
+ advice: "Do not exceed 4g of paracetamol in 24 hours across all products.",
+ },
+ paracetamol: {
+ useCase: "Pain & Fever",
+ genericName: "Paracetamol",
+ brandNames: "Panadol, Tylenol",
+ drugClass: "Analgesic / Antipyretic",
+ dosages: ["500mg"],
+ advice: "Avoid alcohol while taking this medicine.",
+ },
+ "paracetamol-tylenol": {
+ useCase: "Pain & Fever",
+ genericName: "Acetaminophen",
+ brandNames: "Tylenol, Panadol",
+ drugClass: "Analgesic",
+ dosages: ["500mg", "650mg"],
+ },
+ "paracetamol-caffeine": {
+ useCase: "Headache Relief",
+ genericName: "Paracetamol + Caffeine",
+ brandNames: "Panadol Extra",
+ drugClass: "Analgesic combination",
+ dosages: ["500mg / 65mg"],
+ advice: "Contains caffeine — limit other caffeinated drinks.",
+ },
+ snip: {
+ useCase: "Cold & Flu",
+ genericName: "Paracetamol + Pseudoephedrine + Chlorphenamine",
+ brandNames: "SNIP",
+ drugClass: "Decongestant combination",
+ sideEffects: {
+ mild: ["Drowsiness", "Dry mouth", "Dizziness"],
+ severe: ["Rapid heartbeat", "High blood pressure"],
+ },
+ advice: "May cause drowsiness. Do not drive until you know how it affects you.",
+ },
+ metformin: {
+ useCase: "Diabetes Care",
+ genericName: "Metformin hydrochloride",
+ brandNames: "Glucophage, Glumet",
+ drugClass: "Biguanide antidiabetic",
+ dosages: ["500mg", "850mg", "1000mg"],
+ sideEffects: {
+ mild: ["Nausea", "Diarrhoea", "Metallic taste"],
+ severe: ["Lactic acidosis", "Vitamin B12 deficiency"],
+ },
+ advice: "Take with meals to reduce stomach upset. Requires a valid prescription.",
+ },
+ ciprofloxacin: {
+ useCase: "Antibiotic",
+ genericName: "Ciprofloxacin",
+ brandNames: "Cipro, Ciprobay",
+ drugClass: "Fluoroquinolone antibiotic",
+ dosages: ["250mg", "500mg"],
+ sideEffects: {
+ mild: ["Nausea", "Headache", "Dizziness"],
+ severe: ["Tendon rupture", "Nerve damage"],
+ },
+ advice: "Finish the full course even if you feel better.",
+ },
+ azitro: {
+ useCase: "Antibiotic",
+ genericName: "Azithromycin",
+ brandNames: "Zithromax, Azitro",
+ drugClass: "Macrolide antibiotic",
+ dosages: ["250mg", "500mg"],
+ advice: "Usually taken once daily for 3 days. Complete the course as prescribed.",
+ },
+ diclofenac: {
+ useCase: "Pain & Inflammation",
+ genericName: "Diclofenac sodium",
+ brandNames: "Voltaren, Cataflam",
+ drugClass: "NSAID",
+ dosages: ["25mg", "50mg", "75mg"],
+ sideEffects: {
+ mild: ["Indigestion", "Headache", "Dizziness"],
+ severe: ["Stomach bleeding", "Kidney issues"],
+ },
+ advice: "Take after food. Avoid if you have a history of stomach ulcers.",
+ },
+ pantoprazole: {
+ useCase: "Acid Reflux",
+ genericName: "Pantoprazole sodium",
+ brandNames: "Protonix, Pantocid",
+ drugClass: "Proton pump inhibitor",
+ dosages: ["20mg", "40mg"],
+ advice: "Take 30–60 minutes before your first meal of the day.",
+ },
+ desloratidine: {
+ useCase: "Allergy Relief",
+ genericName: "Desloratadine",
+ brandNames: "Clarinex, Aerius",
+ drugClass: "Antihistamine",
+ dosages: ["5mg"],
+ advice: "Non-drowsy for most people, but avoid driving until you're sure.",
+ },
+ "nat-c-vitamin-c": {
+ useCase: "Immune Support",
+ genericName: "Ascorbic acid",
+ brandNames: "Nat C, Redoxon",
+ drugClass: "Vitamin supplement",
+ dosages: ["500mg", "1000mg"],
+ sideEffects: { mild: ["Stomach upset", "Heartburn"], severe: ["Kidney stones (high doses)"] },
+ },
+ gofen: {
+ useCase: "Pain & Inflammation",
+ genericName: "Ibuprofen",
+ brandNames: "Brufen, Advil, Gofen",
+ drugClass: "NSAID",
+ dosages: ["200mg", "400mg"],
+ advice: "Take with food or milk to protect your stomach.",
+ },
+ quemox: {
+ useCase: "Antibiotic",
+ genericName: "Amoxicillin",
+ brandNames: "Amoxil, Quemox",
+ drugClass: "Penicillin antibiotic",
+ dosages: ["250mg", "500mg"],
+ advice: "Tell your pharmacist about any penicillin allergy before use.",
+ },
+ sildenafil: {
+ useCase: "Sexual Wellness",
+ genericName: "Sildenafil citrate",
+ brandNames: "Viagra, Cialis (tadalafil alt.)",
+ drugClass: "PDE5 inhibitor",
+ dosages: ["25mg", "50mg", "100mg"],
+ advice: "Never combine with nitrate heart medicines. Prescription required.",
+ },
+ "ors-sachets": {
+ useCase: "Rehydration",
+ genericName: "Oral rehydration salts",
+ brandNames: "ORS, Hydralyte",
+ drugClass: "Electrolyte replacement",
+ advice: "Dissolve one sachet in 200ml of clean water. Use within 24 hours.",
+ },
+ "cough-syrup": {
+ useCase: "Cough Relief",
+ form: "Syrup",
+ genericName: "Dextromethorphan / Guaifenesin",
+ brandNames: "Robitussin, Benylin",
+ drugClass: "Antitussive / Expectorant",
+ dosages: ["100ml", "200ml"],
+ },
+ "lubricating-eye-drops": {
+ useCase: "Eye Care",
+ form: "Drops",
+ },
+ "eye-drops-lubricating": {
+ useCase: "Eye Care",
+ form: "Drops",
+ genericName: "Carboxymethylcellulose",
+ brandNames: "Refresh Tears, Optive",
+ drugClass: "Ocular lubricant",
+ },
+ "blood-pressure-monitor": {
+ useCase: "Monitoring",
+ form: "Device",
+ genericName: "Upper-arm oscillometric monitor",
+ brandNames: "HealthTech",
+ drugClass: "Class II medical device",
+ },
+ "glucose-meter-kit": {
+ useCase: "Diabetes Care",
+ form: "Device",
+ genericName: "Blood glucose monitoring system",
+ brandNames: "DiaCare",
+ drugClass: "Class II medical device",
+ },
+};
+
+const DEFAULT_SIDE_EFFECTS: DrugFacts["sideEffects"] = {
+ mild: ["Nausea", "Headache", "Mild dizziness"],
+ severe: ["Allergic reaction", "Difficulty breathing"],
+};
+
+const DEFAULT_STORAGE: StorageNote[] = [
+ {
+ icon: "thermometer-outline",
+ title: "Temperature",
+ body: "Store at room temperature, between 20°C and 25°C.",
+ },
+ {
+ icon: "sunny-outline",
+ title: "Light & moisture",
+ body: "Keep in a dry place, away from direct sunlight.",
+ },
+ {
+ icon: "happy-outline",
+ title: "Children",
+ body: "Keep out of reach of children to prevent accidental ingestion.",
+ },
+];
+
+const DEFAULT_DIRECTIONS: DrugFacts["directions"] = [
+ {
+ title: "Check with your pharmacist",
+ body: "Confirm the dose is right for your age, weight and other medicines.",
+ },
+ {
+ title: "Take as directed",
+ body: "Follow the schedule on the label. Do not double up on a missed dose.",
+ },
+ {
+ title: "Take with water",
+ body: "Swallow whole with a full glass of water unless told otherwise.",
+ },
+ {
+ title: "Track your response",
+ body: "Stop and contact us if symptoms persist beyond 3 days.",
+ },
+];
+
+const DEVICE_DIRECTIONS: DrugFacts["directions"] = [
+ { title: "Unbox and inspect", body: "Check all parts are present and undamaged." },
+ { title: "Prepare", body: "Sit still for 5 minutes and rest your arm at heart level." },
+ { title: "Measure", body: "Follow the on-screen prompts and stay quiet during the reading." },
+ { title: "Log the result", body: "Record readings so your pharmacist can review trends." },
+];
+
+/** Deterministic pseudo-stock so the number is stable between renders. */
+function stockFor(product: Product): number {
+ if (!product.inStock) return 0;
+ const seed = product.id
+ .split("")
+ .reduce((total, char) => total + char.charCodeAt(0), 0);
+ return 8 + (seed % 44);
+}
+
+export function getDrugFacts(product: Product): DrugFacts {
+ const override = OVERRIDES[product.slug] ?? {};
+ const isDevice = product.category === "devices" || product.category === "first-aid";
+
+ return {
+ useCase: override.useCase ?? CATEGORY_USE_CASE[product.category] ?? "Healthcare",
+ form: override.form ?? CATEGORY_FORM[product.category] ?? "Unit",
+ genericName: override.genericName ?? product.name,
+ brandNames: override.brandNames ?? product.brand,
+ drugClass: override.drugClass ?? CATEGORY_USE_CASE[product.category] ?? "Healthcare product",
+ dosages: override.dosages ?? [],
+ sideEffects:
+ override.sideEffects ??
+ (isDevice ? { mild: ["Skin irritation"], severe: [] } : DEFAULT_SIDE_EFFECTS),
+ storage: override.storage ?? DEFAULT_STORAGE,
+ directions: override.directions ?? (isDevice ? DEVICE_DIRECTIONS : DEFAULT_DIRECTIONS),
+ stockCount: override.stockCount ?? stockFor(product),
+ advice:
+ override.advice ??
+ (product.requiresPrescription
+ ? "A valid prescription is required. Our pharmacist will verify it before dispatch."
+ : "Speak to our pharmacist if you are pregnant, breastfeeding or taking other medicines."),
+ };
+}
+
+/** Star distribution for the review summary, weighted by the product rating. */
+export function getReviewBreakdown(product: Product) {
+ const weights = [0.62, 0.22, 0.09, 0.04, 0.03];
+ const shift = Math.max(0, Math.round((4.8 - product.rating) * 10)) / 100;
+ return [5, 4, 3, 2, 1].map((stars, index) => {
+ const weight = Math.max(0.01, weights[index] - (index === 0 ? shift : -shift / 4));
+ return { stars, count: Math.max(1, Math.round(product.reviews * weight)) };
+ });
+}
diff --git a/lib/data/products.ts b/lib/data/products.ts
new file mode 100644
index 0000000..f99eb0e
--- /dev/null
+++ b/lib/data/products.ts
@@ -0,0 +1,997 @@
+export type Product = {
+ id: string;
+ slug: string;
+ name: string;
+ brand: string;
+ category: string;
+ description: string;
+ price: number;
+ compareAt?: number;
+ image: string;
+ rating: number;
+ reviews: number;
+ badge?: "sale" | "new" | "bestseller";
+ requiresPrescription?: boolean;
+ inStock: boolean;
+ sku: string;
+ unit: string;
+};
+
+const u = (id: string) =>
+ `https://images.unsplash.com/${id}?w=600&q=80`;
+
+export const products: Product[] = [
+ {
+ id: "p1",
+ slug: "panadol-advance",
+ name: "Panadol Advance",
+ brand: "GSK",
+ category: "medicines",
+ description:
+ "Fast-acting paracetamol tablets for relief of mild to moderate pain and fever.",
+ price: 85,
+ compareAt: 110,
+ image: "https://gishen-ecom.vercel.app/products/panadol-advance.jpg",
+ rating: 4.8,
+ reviews: 214,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-PAN-ADV",
+ unit: "16 tablets",
+ },
+ {
+ id: "p2",
+ slug: "paracetamol",
+ name: "Paracetamol",
+ brand: "Generic",
+ category: "medicines",
+ description: "Reliable pain and fever relief for everyday use.",
+ price: 35,
+ image: "https://gishen-ecom.vercel.app/products/paracetamol.jpg",
+ rating: 4.6,
+ reviews: 189,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-PCM-500",
+ unit: "20 tablets",
+ },
+ {
+ id: "p3",
+ slug: "paracetamol-tylenol",
+ name: "Paracetamol Tylenol",
+ brand: "Tylenol",
+ category: "medicines",
+ description: "Trusted acetaminophen formula for pain and fever.",
+ price: 120,
+ compareAt: 145,
+ image: "https://gishen-ecom.vercel.app/products/paracetamol-tylenol.jpg",
+ rating: 4.7,
+ reviews: 98,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-TYL-PCM",
+ unit: "24 tablets",
+ },
+ {
+ id: "p4",
+ slug: "paracetamol-caffeine",
+ name: "Paracetamol + Caffeine",
+ brand: "Generic",
+ category: "medicines",
+ description: "Enhanced pain relief combining paracetamol with caffeine.",
+ price: 55,
+ image: "https://gishen-ecom.vercel.app/products/paracetamol-caffein.jpg",
+ rating: 4.5,
+ reviews: 67,
+ inStock: true,
+ sku: "GSH-PCM-CAF",
+ unit: "20 tablets",
+ },
+ {
+ id: "p5",
+ slug: "snip",
+ name: "SNIP Cold & Flu",
+ brand: "SNIP",
+ category: "medicines",
+ description:
+ "Paracetamol, pseudoephedrine and chlorphenamine for cold and flu symptoms.",
+ price: 95,
+ compareAt: 120,
+ image: "https://gishen-ecom.vercel.app/products/snip-pcm-pseudoephedrine-chlorphenamine.jpg",
+ rating: 4.6,
+ reviews: 142,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-SNIP-01",
+ unit: "12 tablets",
+ },
+ {
+ id: "p6",
+ slug: "paracetamol-pseudoephedrine-snip",
+ name: "Paracetamol-Pseudoephedrine (SNIP)",
+ brand: "SNIP",
+ category: "medicines",
+ description: "Relieves nasal congestion with pain and fever control.",
+ price: 90,
+ image: "https://gishen-ecom.vercel.app/products/paracetamol-pseudoephedrine-snip.jpg",
+ rating: 4.4,
+ reviews: 76,
+ inStock: true,
+ sku: "GSH-SNIP-02",
+ unit: "12 tablets",
+ },
+ {
+ id: "p7",
+ slug: "metformin",
+ name: "Metformin",
+ brand: "Generic",
+ category: "diabetic",
+ description: "Oral antidiabetic medication for type 2 diabetes management.",
+ price: 75,
+ image: "https://gishen-ecom.vercel.app/products/metformin.jpg",
+ rating: 4.7,
+ reviews: 203,
+ badge: "bestseller",
+ requiresPrescription: true,
+ inStock: true,
+ sku: "GSH-MET-500",
+ unit: "30 tablets",
+ },
+ {
+ id: "p8",
+ slug: "ciprofloxacin",
+ name: "Ciprofloxacin",
+ brand: "Generic",
+ category: "medicines",
+ description: "Broad-spectrum antibiotic for bacterial infections.",
+ price: 140,
+ image: "https://gishen-ecom.vercel.app/products/ciprofloxacin.jpg",
+ rating: 4.5,
+ reviews: 88,
+ requiresPrescription: true,
+ inStock: true,
+ sku: "GSH-CIP-500",
+ unit: "10 tablets",
+ },
+ {
+ id: "p9",
+ slug: "azitro",
+ name: "Azitro (Azithromycin)",
+ brand: "Azitro",
+ category: "medicines",
+ description: "Macrolide antibiotic commonly used for respiratory infections.",
+ price: 180,
+ compareAt: 220,
+ image: "https://gishen-ecom.vercel.app/products/azitro.jpg",
+ rating: 4.6,
+ reviews: 112,
+ badge: "sale",
+ requiresPrescription: true,
+ inStock: true,
+ sku: "GSH-AZI-500",
+ unit: "3 tablets",
+ },
+ {
+ id: "p10",
+ slug: "diclofenac",
+ name: "Diclofenac",
+ brand: "Generic",
+ category: "medicines",
+ description: "NSAID for pain, inflammation and joint discomfort.",
+ price: 60,
+ image: "https://gishen-ecom.vercel.app/products/diclofenac.jpg",
+ rating: 4.5,
+ reviews: 156,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-DIC-50",
+ unit: "20 tablets",
+ },
+ {
+ id: "p11",
+ slug: "albendazole",
+ name: "Albendazole",
+ brand: "Generic",
+ category: "medicines",
+ description: "Anthelmintic treatment for worm infections.",
+ price: 45,
+ image: "https://gishen-ecom.vercel.app/products/albendazole.jpg",
+ rating: 4.4,
+ reviews: 91,
+ inStock: true,
+ sku: "GSH-ALB-400",
+ unit: "1 tablet",
+ },
+ {
+ id: "p12",
+ slug: "pantoprazole",
+ name: "Pantoprazole",
+ brand: "Generic",
+ category: "medicines",
+ description: "Proton pump inhibitor for acid reflux and ulcers.",
+ price: 110,
+ image: "https://gishen-ecom.vercel.app/products/pantoprazole.jpg",
+ rating: 4.6,
+ reviews: 134,
+ requiresPrescription: true,
+ inStock: true,
+ sku: "GSH-PAN-40",
+ unit: "14 tablets",
+ },
+ {
+ id: "p13",
+ slug: "desloratidine",
+ name: "Desloratidine",
+ brand: "Generic",
+ category: "medicines",
+ description: "Non-drowsy antihistamine for allergy relief.",
+ price: 95,
+ image: "https://gishen-ecom.vercel.app/products/desloratidine.jpg",
+ rating: 4.5,
+ reviews: 72,
+ badge: "new",
+ inStock: true,
+ sku: "GSH-DES-5",
+ unit: "10 tablets",
+ },
+ {
+ id: "p14",
+ slug: "nat-c-vitamin-c",
+ name: "Nat C (Vitamin C)",
+ brand: "Nat C",
+ category: "vitamins",
+ description: "Vitamin C supplement to support immunity and recovery.",
+ price: 150,
+ compareAt: 180,
+ image: "https://gishen-ecom.vercel.app/products/nat-c-vitamin-c.jpg",
+ rating: 4.8,
+ reviews: 267,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-NATC-01",
+ unit: "30 tablets",
+ },
+ {
+ id: "p15",
+ slug: "vigafen",
+ name: "Vigafen",
+ brand: "Vigafen",
+ category: "medicines",
+ description: "Combination analgesic for headache and body pain.",
+ price: 70,
+ image: "https://gishen-ecom.vercel.app/products/vigafen.jpg",
+ rating: 4.3,
+ reviews: 54,
+ inStock: true,
+ sku: "GSH-VIG-01",
+ unit: "20 tablets",
+ },
+ {
+ id: "p16",
+ slug: "gofen",
+ name: "Gofen",
+ brand: "Gofen",
+ category: "medicines",
+ description: "Ibuprofen soft gel capsules for pain and inflammation.",
+ price: 125,
+ compareAt: 150,
+ image: "https://gishen-ecom.vercel.app/products/gofen.jpg",
+ rating: 4.7,
+ reviews: 118,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-GOF-400",
+ unit: "10 softgels",
+ },
+ {
+ id: "p17",
+ slug: "quemox",
+ name: "Quemox",
+ brand: "Quemox",
+ category: "medicines",
+ description: "Amoxicillin antibiotic for bacterial infections.",
+ price: 160,
+ image: "https://gishen-ecom.vercel.app/products/quemox.jpg",
+ rating: 4.5,
+ reviews: 83,
+ requiresPrescription: true,
+ inStock: true,
+ sku: "GSH-QUE-500",
+ unit: "21 capsules",
+ },
+ {
+ id: "p18",
+ slug: "olit",
+ name: "Olit",
+ brand: "Olit",
+ category: "medicines",
+ description: "Gastrointestinal support medication.",
+ price: 100,
+ image: "https://gishen-ecom.vercel.app/products/olit.jpg",
+ rating: 4.2,
+ reviews: 41,
+ inStock: true,
+ sku: "GSH-OLIT-01",
+ unit: "14 tablets",
+ },
+ {
+ id: "p19",
+ slug: "degra",
+ name: "Degra",
+ brand: "Degra",
+ category: "medicines",
+ description: "Digestive relief support formula.",
+ price: 115,
+ image: "https://gishen-ecom.vercel.app/products/degra.jpg",
+ rating: 4.3,
+ reviews: 39,
+ badge: "new",
+ inStock: true,
+ sku: "GSH-DEG-01",
+ unit: "10 sachets",
+ },
+ {
+ id: "p20",
+ slug: "almetamin",
+ name: "Almetamin",
+ brand: "Almetamin",
+ category: "medicines",
+ description: "Antihistamine for allergy and cold symptoms.",
+ price: 65,
+ image: "https://gishen-ecom.vercel.app/products/almetamin.jpg",
+ rating: 4.4,
+ reviews: 58,
+ inStock: true,
+ sku: "GSH-ALM-01",
+ unit: "20 tablets",
+ },
+ {
+ id: "p21",
+ slug: "mela-one-tablet",
+ name: "Mela One Tablet",
+ brand: "Mela",
+ category: "medicines",
+ description: "Single-dose treatment tablet as directed by a pharmacist.",
+ price: 80,
+ image: "https://gishen-ecom.vercel.app/products/mela-one-tablet.jpg",
+ rating: 4.1,
+ reviews: 33,
+ inStock: true,
+ sku: "GSH-MELA-01",
+ unit: "1 tablet",
+ },
+ {
+ id: "p22",
+ slug: "sildenafil",
+ name: "Sildenafil",
+ brand: "Generic",
+ category: "wellness",
+ description: "Prescription medication for erectile dysfunction.",
+ price: 250,
+ image: "https://gishen-ecom.vercel.app/products/sildenafil.jpg",
+ rating: 4.6,
+ reviews: 97,
+ requiresPrescription: true,
+ inStock: true,
+ sku: "GSH-SIL-100",
+ unit: "4 tablets",
+ },
+ {
+ id: "p23",
+ slug: "hiwot-trust-condom",
+ name: "Hiwot Trust Condom",
+ brand: "Hiwot Trust",
+ category: "wellness",
+ description: "Trusted protection condoms for sexual wellness.",
+ price: 50,
+ image: "https://gishen-ecom.vercel.app/products/hiwot-trust-condom.jpg",
+ rating: 4.7,
+ reviews: 176,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-HTC-01",
+ unit: "3 pack",
+ },
+ {
+ id: "p24",
+ slug: "royal-face-mask",
+ name: "Royal Face Mask",
+ brand: "Royal",
+ category: "devices",
+ description: "Protective face masks for everyday hygiene.",
+ price: 40,
+ compareAt: 60,
+ image: "https://gishen-ecom.vercel.app/products/royal-face-mask.jpg",
+ rating: 4.5,
+ reviews: 210,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-RFM-50",
+ unit: "50 pcs",
+ },
+ {
+ id: "p25",
+ slug: "examination-glove-medium",
+ name: "Examination Glove Medium",
+ brand: "MedGloves",
+ category: "devices",
+ description: "Disposable examination gloves, medium size.",
+ price: 220,
+ image: "https://gishen-ecom.vercel.app/products/examination-glove-medium.jpg",
+ rating: 4.6,
+ reviews: 64,
+ inStock: true,
+ sku: "GSH-GLV-M",
+ unit: "100 pcs",
+ },
+ {
+ id: "p26",
+ slug: "surgical-glove",
+ name: "Surgical Glove",
+ brand: "MedGloves",
+ category: "devices",
+ description: "Sterile surgical gloves for clinical use.",
+ price: 280,
+ image: "https://gishen-ecom.vercel.app/products/surgical-glave.jpg",
+ rating: 4.5,
+ reviews: 48,
+ inStock: true,
+ sku: "GSH-SGL-M",
+ unit: "50 pairs",
+ },
+ {
+ id: "p27",
+ slug: "first-aid-plaster",
+ name: "First Aid Plaster",
+ brand: "CareAid",
+ category: "first-aid",
+ description: "Assorted adhesive plasters for minor cuts and scrapes.",
+ price: 45,
+ image: "https://gishen-ecom.vercel.app/products/first-aid-plaster.jpg",
+ rating: 4.6,
+ reviews: 122,
+ badge: "new",
+ inStock: true,
+ sku: "GSH-FAP-01",
+ unit: "20 strips",
+ },
+ // Expanded curated OTC / wellness catalog (licensed Unsplash imagery)
+ {
+ id: "p28",
+ slug: "vitamin-d3",
+ name: "Vitamin D3 1000 IU",
+ brand: "Wellness Plus",
+ category: "vitamins",
+ description: "Supports bone health and immune function.",
+ price: 280,
+ compareAt: 320,
+ image: u("photo-1559757148-5c350d0d3c56"),
+ rating: 4.7,
+ reviews: 145,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-VD3-01",
+ unit: "60 softgels",
+ },
+ {
+ id: "p29",
+ slug: "omega-3-fish-oil",
+ name: "Omega-3 Fish Oil",
+ brand: "Wellness Plus",
+ category: "vitamins",
+ description: "EPA & DHA support for heart and brain health.",
+ price: 450,
+ image: u("photo-1505751172876-fa1923c5c528"),
+ rating: 4.8,
+ reviews: 198,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-OM3-01",
+ unit: "90 softgels",
+ },
+ {
+ id: "p30",
+ slug: "multivitamin-daily",
+ name: "Daily Multivitamin",
+ brand: "VitaDay",
+ category: "vitamins",
+ description: "Complete daily micronutrient support for adults.",
+ price: 320,
+ image: u("photo-1471864190281-a93a3070b6de"),
+ rating: 4.6,
+ reviews: 231,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-MVIT-01",
+ unit: "30 tablets",
+ },
+ {
+ id: "p31",
+ slug: "zinc-tablets",
+ name: "Zinc Tablets 50mg",
+ brand: "VitaDay",
+ category: "vitamins",
+ description: "Zinc supplement to support immunity.",
+ price: 180,
+ image: u("photo-1585435557343-3b092031a831"),
+ rating: 4.4,
+ reviews: 87,
+ inStock: true,
+ sku: "GSH-ZNC-50",
+ unit: "30 tablets",
+ },
+ {
+ id: "p32",
+ slug: "iron-folic-acid",
+ name: "Iron + Folic Acid",
+ brand: "VitaDay",
+ category: "vitamins",
+ description: "Supports healthy blood and prenatal nutrition needs.",
+ price: 160,
+ image: u("photo-1587854692152-cbe660dbde88"),
+ rating: 4.5,
+ reviews: 104,
+ inStock: true,
+ sku: "GSH-IRN-01",
+ unit: "30 tablets",
+ },
+ {
+ id: "p33",
+ slug: "calcium-magnesium",
+ name: "Calcium + Magnesium",
+ brand: "BoneCare",
+ category: "vitamins",
+ description: "Mineral blend for bone and muscle support.",
+ price: 290,
+ image: u("photo-1628771065518-0d82f1938462"),
+ rating: 4.5,
+ reviews: 76,
+ badge: "new",
+ inStock: true,
+ sku: "GSH-CAM-01",
+ unit: "60 tablets",
+ },
+ {
+ id: "p34",
+ slug: "hand-sanitizer-500",
+ name: "Hand Sanitizer 500ml",
+ brand: "CleanHands",
+ category: "personal-care",
+ description: "Alcohol-based sanitizer for on-the-go hygiene.",
+ price: 120,
+ compareAt: 150,
+ image: u("photo-1582719471384-894fbb16e074"),
+ rating: 4.6,
+ reviews: 188,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-SAN-500",
+ unit: "500 ml",
+ },
+ {
+ id: "p35",
+ slug: "moisturizing-lotion",
+ name: "Moisturizing Body Lotion",
+ brand: "DermaSoft",
+ category: "personal-care",
+ description: "Daily hydrating lotion for dry and sensitive skin.",
+ price: 240,
+ image: u("photo-1556228578-0d85b1a4d571"),
+ rating: 4.7,
+ reviews: 132,
+ inStock: true,
+ sku: "GSH-LOT-01",
+ unit: "400 ml",
+ },
+ {
+ id: "p36",
+ slug: "sunscreen-spf50",
+ name: "Sunscreen SPF 50",
+ brand: "DermaSoft",
+ category: "personal-care",
+ description: "Broad-spectrum sun protection for face and body.",
+ price: 380,
+ image: u("photo-1556228720-195a672e8a03"),
+ rating: 4.8,
+ reviews: 165,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-SPF-50",
+ unit: "100 ml",
+ },
+ {
+ id: "p37",
+ slug: "antiseptic-mouthwash",
+ name: "Antiseptic Mouthwash",
+ brand: "OralCare",
+ category: "personal-care",
+ description: "Freshens breath and supports oral hygiene.",
+ price: 160,
+ image: u("photo-1607613009820-a29f7bb81c04"),
+ rating: 4.4,
+ reviews: 79,
+ inStock: true,
+ sku: "GSH-MW-01",
+ unit: "500 ml",
+ },
+ {
+ id: "p38",
+ slug: "shampoo-gentle",
+ name: "Gentle Care Shampoo",
+ brand: "HairWell",
+ category: "personal-care",
+ description: "Mild shampoo suitable for daily use.",
+ price: 210,
+ image: u("photo-1535585209827-a15fcdbc4c2d"),
+ rating: 4.3,
+ reviews: 91,
+ badge: "new",
+ inStock: true,
+ sku: "GSH-SHP-01",
+ unit: "400 ml",
+ },
+ {
+ id: "p39",
+ slug: "blood-pressure-monitor",
+ name: "Digital Blood Pressure Monitor",
+ brand: "HealthTech",
+ category: "devices",
+ description: "Upper-arm digital BP monitor for home use.",
+ price: 1850,
+ compareAt: 2100,
+ image: u("photo-1584362917165-526a968579e8"),
+ rating: 4.7,
+ reviews: 84,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-BPM-01",
+ unit: "1 unit",
+ },
+ {
+ id: "p40",
+ slug: "pulse-oximeter",
+ name: "Pulse Oximeter",
+ brand: "HealthTech",
+ category: "devices",
+ description: "Fingertip SpO2 and pulse rate monitor.",
+ price: 950,
+ image: u("photo-1666214280557-f1b5022eb634"),
+ rating: 4.6,
+ reviews: 113,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-OXM-01",
+ unit: "1 unit",
+ },
+ {
+ id: "p41",
+ slug: "digital-thermometer",
+ name: "Digital Thermometer",
+ brand: "HealthTech",
+ category: "devices",
+ description: "Fast-read digital thermometer for family use.",
+ price: 280,
+ image: u("photo-1584017911766-d451b3d0e843"),
+ rating: 4.5,
+ reviews: 156,
+ inStock: true,
+ sku: "GSH-THM-01",
+ unit: "1 unit",
+ },
+ {
+ id: "p42",
+ slug: "glucose-meter-kit",
+ name: "Blood Glucose Meter Kit",
+ brand: "DiaCare",
+ category: "diabetic",
+ description: "Home glucose monitoring kit with strips starter pack.",
+ price: 1450,
+ image: u("photo-1579684385127-1ef15d508118"),
+ rating: 4.7,
+ reviews: 99,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-BGM-01",
+ unit: "1 kit",
+ },
+ {
+ id: "p43",
+ slug: "glucose-test-strips",
+ name: "Glucose Test Strips",
+ brand: "DiaCare",
+ category: "diabetic",
+ description: "Compatible test strips for DiaCare meters.",
+ price: 420,
+ image: u("photo-1631549916768-4119b2e5f926"),
+ rating: 4.5,
+ reviews: 67,
+ inStock: true,
+ sku: "GSH-GTS-50",
+ unit: "50 strips",
+ },
+ {
+ id: "p44",
+ slug: "baby-lotion",
+ name: "Baby Soft Lotion",
+ brand: "TinyCare",
+ category: "baby",
+ description: "Hypoallergenic lotion for delicate baby skin.",
+ price: 260,
+ image: u("photo-1515488042361-ee00e0ddd4e4"),
+ rating: 4.8,
+ reviews: 143,
+ badge: "new",
+ inStock: true,
+ sku: "GSH-BBL-01",
+ unit: "200 ml",
+ },
+ {
+ id: "p45",
+ slug: "baby-wipes",
+ name: "Sensitive Baby Wipes",
+ brand: "TinyCare",
+ category: "baby",
+ description: "Fragrance-free wipes for sensitive skin.",
+ price: 95,
+ compareAt: 120,
+ image: u("photo-1544367567-0f2fcb009e0b"),
+ rating: 4.6,
+ reviews: 201,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-BBW-80",
+ unit: "80 wipes",
+ },
+ {
+ id: "p46",
+ slug: "diaper-rash-cream",
+ name: "Diaper Rash Cream",
+ brand: "TinyCare",
+ category: "baby",
+ description: "Soothing cream to protect against diaper irritation.",
+ price: 180,
+ image: u("photo-1492725764893-90b379c2b6e7"),
+ rating: 4.7,
+ reviews: 88,
+ inStock: true,
+ sku: "GSH-DRC-01",
+ unit: "100 g",
+ },
+ {
+ id: "p47",
+ slug: "first-aid-kit",
+ name: "Family First Aid Kit",
+ brand: "CareAid",
+ category: "first-aid",
+ description: "Compact kit with essentials for home and travel.",
+ price: 650,
+ compareAt: 780,
+ image: u("photo-1603398938378-e54eab446dde"),
+ rating: 4.8,
+ reviews: 124,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-FAK-01",
+ unit: "1 kit",
+ },
+ {
+ id: "p48",
+ slug: "antiseptic-solution",
+ name: "Antiseptic Solution",
+ brand: "CareAid",
+ category: "first-aid",
+ description: "Wound cleansing antiseptic for first aid use.",
+ price: 90,
+ image: u("photo-1584308666744-24d5c474f2ae"),
+ rating: 4.5,
+ reviews: 96,
+ inStock: true,
+ sku: "GSH-ANT-250",
+ unit: "250 ml",
+ },
+ {
+ id: "p49",
+ slug: "cotton-wool",
+ name: "Surgical Cotton Wool",
+ brand: "CareAid",
+ category: "first-aid",
+ description: "Absorbent cotton for wound care and cosmetics.",
+ price: 55,
+ image: u("photo-1576671081837-49000212a370"),
+ rating: 4.4,
+ reviews: 71,
+ inStock: true,
+ sku: "GSH-CTN-100",
+ unit: "100 g",
+ },
+ {
+ id: "p50",
+ slug: "ors-sachets",
+ name: "ORS Sachets",
+ brand: "HydraCare",
+ category: "medicines",
+ description: "Oral rehydration salts for dehydration support.",
+ price: 40,
+ image: u("photo-1585435557343-3b092031a831"),
+ rating: 4.7,
+ reviews: 158,
+ badge: "bestseller",
+ inStock: true,
+ sku: "GSH-ORS-10",
+ unit: "10 sachets",
+ },
+ {
+ id: "p51",
+ slug: "cough-syrup",
+ name: "Cough Syrup",
+ brand: "RespiCare",
+ category: "medicines",
+ description: "Soothing syrup for dry and productive coughs.",
+ price: 135,
+ image: u("photo-1587854692152-cbe660dbde88"),
+ rating: 4.4,
+ reviews: 109,
+ inStock: true,
+ sku: "GSH-CGH-100",
+ unit: "100 ml",
+ },
+ {
+ id: "p52",
+ slug: "antacid-chewable",
+ name: "Antacid Chewable",
+ brand: "GastroEase",
+ category: "medicines",
+ description: "Fast relief from heartburn and indigestion.",
+ price: 70,
+ image: u("photo-1471864190281-a93a3070b6de"),
+ rating: 4.5,
+ reviews: 134,
+ inStock: true,
+ sku: "GSH-ANTAC-01",
+ unit: "24 tablets",
+ },
+ {
+ id: "p53",
+ slug: "eye-drops-lubricating",
+ name: "Lubricating Eye Drops",
+ brand: "OptiClear",
+ category: "medicines",
+ description: "Relief for dry, irritated eyes.",
+ price: 190,
+ badge: "new",
+ image: u("photo-1576602976047-174e57a47881"),
+ rating: 4.6,
+ reviews: 62,
+ inStock: true,
+ sku: "GSH-EYE-01",
+ unit: "10 ml",
+ },
+ {
+ id: "p54",
+ slug: "protein-powder",
+ name: "Nutrition Protein Powder",
+ brand: "NutriStrong",
+ category: "vitamins",
+ description: "High-quality protein blend for recovery and wellness.",
+ price: 1250,
+ compareAt: 1400,
+ image: u("photo-1593095948071-474c5cc2989d"),
+ rating: 4.7,
+ reviews: 77,
+ badge: "sale",
+ inStock: true,
+ sku: "GSH-PRO-01",
+ unit: "1 kg",
+ },
+ {
+ id: "p55",
+ slug: "electrolyte-drink",
+ name: "Electrolyte Hydration Mix",
+ brand: "HydraCare",
+ category: "vitamins",
+ description: "Replenishes electrolytes after illness or exercise.",
+ price: 85,
+ image: u("photo-1628771065518-0d82f1938462"),
+ rating: 4.5,
+ reviews: 93,
+ inStock: true,
+ sku: "GSH-ELY-01",
+ unit: "10 sachets",
+ },
+ {
+ id: "p56",
+ slug: "pregnancy-test",
+ name: "Pregnancy Test Kit",
+ brand: "QuickCheck",
+ category: "devices",
+ description: "Rapid home pregnancy test with clear results.",
+ price: 95,
+ image: u("photo-1579154204601-01588f351e67"),
+ rating: 4.6,
+ reviews: 148,
+ inStock: true,
+ sku: "GSH-PTK-01",
+ unit: "1 kit",
+ },
+ {
+ id: "p57",
+ slug: "compression-socks",
+ name: "Compression Socks",
+ brand: "CircuFit",
+ category: "devices",
+ description: "Supportive socks for circulation and travel comfort.",
+ price: 340,
+ image: u("photo-1576091160550-2173dba999ef"),
+ rating: 4.3,
+ reviews: 45,
+ badge: "new",
+ inStock: true,
+ sku: "GSH-CSK-01",
+ unit: "1 pair",
+ },
+ {
+ id: "p58",
+ slug: "hot-water-bottle",
+ name: "Hot Water Bottle",
+ brand: "ComfortCare",
+ category: "first-aid",
+ description: "Classic hot water bottle for warmth and comfort.",
+ price: 220,
+ image: u("photo-1516549655169-df83a0774514"),
+ rating: 4.4,
+ reviews: 58,
+ inStock: true,
+ sku: "GSH-HWB-01",
+ unit: "1 unit",
+ },
+ {
+ id: "p59",
+ slug: "inhaler-spacer",
+ name: "Inhaler Spacer",
+ brand: "RespiCare",
+ category: "devices",
+ description: "Spacer chamber to improve inhaler medication delivery.",
+ price: 480,
+ image: u("photo-1584308666744-24d5c474f2ae"),
+ rating: 4.5,
+ reviews: 36,
+ inStock: true,
+ sku: "GSH-ISP-01",
+ unit: "1 unit",
+ },
+ {
+ id: "p60",
+ slug: "lip-balm-medicated",
+ name: "Medicated Lip Balm",
+ brand: "DermaSoft",
+ category: "personal-care",
+ description: "Soothing balm for dry and cracked lips.",
+ price: 65,
+ image: u("photo-1596755389378-c31d21fd1273"),
+ rating: 4.6,
+ reviews: 112,
+ inStock: true,
+ sku: "GSH-LIP-01",
+ unit: "1 stick",
+ },
+];
+
+export function getProductBySlug(slug: string) {
+ return products.find((p) => p.slug === slug);
+}
+
+export function getProductsByCategory(category: string) {
+ return products.filter((p) => p.category === category);
+}
+
+export function searchProducts(query: string) {
+ const q = query.toLowerCase().trim();
+ if (!q) return products;
+ return products.filter(
+ (p) =>
+ p.name.toLowerCase().includes(q) ||
+ p.brand.toLowerCase().includes(q) ||
+ p.sku.toLowerCase().includes(q) ||
+ p.description.toLowerCase().includes(q),
+ );
+}
diff --git a/lib/data/seed.ts b/lib/data/seed.ts
new file mode 100644
index 0000000..1aaeec1
--- /dev/null
+++ b/lib/data/seed.ts
@@ -0,0 +1,291 @@
+import type { CartItem } from "@/lib/stores/cartStore";
+import type { EmergencyContact } from "@/lib/stores/emergencyContactStore";
+import type { FamilyMember } from "@/lib/stores/familyStore";
+import type { Order } from "@/lib/stores/ordersStore";
+import type {
+ DoseLog,
+ Prescription,
+ Reminder,
+} from "@/lib/stores/prescriptionStore";
+import type { RefillSubscription } from "@/lib/stores/subscriptionStore";
+import { products } from "@/lib/data/products";
+
+function daysAgo(n: number) {
+ const d = new Date();
+ d.setDate(d.getDate() - n);
+ return d.toISOString();
+}
+
+function daysFromNow(n: number) {
+ const d = new Date();
+ d.setDate(d.getDate() + n);
+ return d.toISOString();
+}
+
+function hoursFromNow(n: number) {
+ const d = new Date();
+ d.setHours(d.getHours() + n);
+ return d.toISOString();
+}
+
+const panadol = products.find((p) => p.id === "p1")!;
+const metformin = products.find((p) => p.id === "p7")!;
+const vitaminC = products.find((p) => p.id === "p14")!;
+const azitro = products.find((p) => p.id === "p9")!;
+const gofen = products.find((p) => p.id === "p16")!;
+
+function asCartItem(product: (typeof products)[0], quantity: number): CartItem {
+ return {
+ productId: product.id,
+ slug: product.slug,
+ name: product.name,
+ price: product.price,
+ image: product.image,
+ unit: product.unit,
+ quantity,
+ requiresPrescription: product.requiresPrescription,
+ };
+}
+
+export const seedPrescriptions: Prescription[] = [
+ {
+ id: "rx_demo_metformin",
+ patientName: "Kirukib Abebe",
+ memberId: null,
+ medicineName: "Metformin 500mg",
+ medicines: [
+ { name: "Metformin 500mg", status: "ready" },
+ { name: "Vitamin B12", status: "ready" },
+ ],
+ imageUris: [
+ "https://images.unsplash.com/photo-1584308666744-24d5c474f2ae?w=800&q=80",
+ ],
+ daysSupply: 30,
+ lastFilledAt: daysAgo(25),
+ status: "filled",
+ notes: "Take with meals. Monitor fasting glucose weekly.",
+ createdAt: daysAgo(26),
+ },
+ {
+ id: "rx_demo_azitro",
+ patientName: "Kirukib Abebe",
+ memberId: null,
+ medicineName: "Azithromycin 500mg",
+ medicines: [
+ { name: "Azithromycin 500mg", status: "ready" },
+ { name: "Cough syrup", status: "review" },
+ ],
+ imageUris: [
+ "https://images.unsplash.com/photo-1587854692152-cbe660dbde88?w=800&q=80",
+ ],
+ daysSupply: 3,
+ lastFilledAt: daysAgo(1),
+ status: "approved",
+ notes: "3-day course. Finish even if symptoms improve.",
+ createdAt: daysAgo(2),
+ },
+ {
+ id: "rx_demo_pending",
+ patientName: "Sara Abebe",
+ memberId: "fam_demo_sara",
+ medicineName: "Amoxicillin 500mg",
+ medicines: [
+ { name: "Amoxicillin 500mg", status: "review" },
+ { name: "ORS sachets", status: "ready" },
+ ],
+ imageUris: [
+ "https://images.unsplash.com/photo-1471864190281-a93a3070b6de?w=800&q=80",
+ ],
+ daysSupply: 7,
+ lastFilledAt: null,
+ status: "under_review",
+ notes: "Pharmacist verifying dosage for pediatric use.",
+ createdAt: daysAgo(0),
+ },
+];
+
+export const seedReminders: Reminder[] = [
+ {
+ id: "rem_demo_metformin",
+ prescriptionId: "rx_demo_metformin",
+ medicineName: "Metformin 500mg",
+ times: ["08:00", "20:00"],
+ daysOfWeek: [0, 1, 2, 3, 4, 5, 6],
+ graceMinutes: 30,
+ escalateOnMiss: true,
+ memberId: null,
+ enabled: true,
+ },
+ {
+ id: "rem_demo_azitro",
+ prescriptionId: "rx_demo_azitro",
+ medicineName: "Azithromycin 500mg",
+ times: ["09:00"],
+ daysOfWeek: [1, 2, 3],
+ graceMinutes: 20,
+ escalateOnMiss: true,
+ memberId: null,
+ enabled: true,
+ },
+];
+
+export const seedDoseLogs: DoseLog[] = [
+ {
+ id: "dose_demo_1",
+ reminderId: "rem_demo_metformin",
+ scheduledAt: hoursFromNow(-2),
+ status: "taken",
+ confirmedAt: hoursFromNow(-1.8),
+ },
+ {
+ id: "dose_demo_2",
+ reminderId: "rem_demo_metformin",
+ scheduledAt: hoursFromNow(4),
+ status: "pending",
+ },
+ {
+ id: "dose_demo_3",
+ reminderId: "rem_demo_azitro",
+ scheduledAt: hoursFromNow(1),
+ status: "pending",
+ },
+];
+
+export const seedOrders: Order[] = [
+ {
+ id: "ord_demo_active",
+ createdAt: daysAgo(0),
+ items: [asCartItem(panadol, 2), asCartItem(vitaminC, 1)],
+ subtotal: panadol.price * 2 + vitaminC.price,
+ deliveryFee: 80,
+ discount: 0,
+ total: panadol.price * 2 + vitaminC.price + 80,
+ fulfillment: "delivery",
+ branchId: "bole",
+ areaLabel: "Bole, Addis Ababa",
+ addressLine: "Rwanda St, Building 12, Apt 4B · Near Edna Mall",
+ paymentMethod: "chapa",
+ status: "dispatched",
+ riderAssigned: true,
+ customerName: "Kirukib Abebe",
+ customerPhone: "+251911000000",
+ notes: "Leave with security if I'm out",
+ },
+ {
+ id: "ord_demo_pickup",
+ createdAt: daysAgo(3),
+ items: [asCartItem(metformin, 1)],
+ subtotal: metformin.price,
+ deliveryFee: 0,
+ discount: 0,
+ total: metformin.price,
+ fulfillment: "pickup",
+ branchId: "cmc",
+ areaLabel: "CMC Michael",
+ paymentMethod: "pay_at_branch",
+ status: "confirmed",
+ riderAssigned: false,
+ customerName: "Kirukib Abebe",
+ customerPhone: "+251911000000",
+ notes: "Prescription refill — patient ID on file",
+ },
+ {
+ id: "ord_demo_done",
+ createdAt: daysAgo(12),
+ items: [asCartItem(gofen, 1), asCartItem(azitro, 1)],
+ subtotal: gofen.price + azitro.price,
+ deliveryFee: 80,
+ discount: 32,
+ voucherCode: "GISHEN10",
+ total: gofen.price + azitro.price + 80 - 32,
+ fulfillment: "delivery",
+ branchId: "mexico",
+ areaLabel: "Mexico Square",
+ addressLine: "Gabon St, Yaltopia Tower, Floor 6",
+ paymentMethod: "telebirr",
+ status: "delivered",
+ riderAssigned: true,
+ customerName: "Kirukib Abebe",
+ customerPhone: "+251911000000",
+ },
+];
+
+export const seedFamily: FamilyMember[] = [
+ {
+ id: "fam_demo_sara",
+ name: "Sara Abebe",
+ relationship: "spouse",
+ phone: "+251911223344",
+ status: "accepted",
+ },
+ {
+ id: "fam_demo_yonas",
+ name: "Yonas Abebe",
+ relationship: "child",
+ phone: "+251922334455",
+ status: "accepted",
+ },
+ {
+ id: "fam_demo_pending",
+ name: "Hanna Bekele",
+ relationship: "parent",
+ phone: "+251933445566",
+ status: "pending",
+ },
+];
+
+export const seedSubscriptions: RefillSubscription[] = [
+ {
+ id: "sub_demo_metformin",
+ productId: "p7",
+ productName: "Metformin",
+ quantity: 1,
+ frequencyDays: 30,
+ fulfillment: "delivery",
+ paymentMethod: "chapa",
+ memberId: null,
+ status: "active",
+ nextFulfillmentAt: daysFromNow(5),
+ },
+ {
+ id: "sub_demo_vitc",
+ productId: "p14",
+ productName: "Nat C (Vitamin C)",
+ quantity: 2,
+ frequencyDays: 60,
+ fulfillment: "pickup",
+ paymentMethod: "telebirr",
+ memberId: null,
+ status: "paused",
+ nextFulfillmentAt: daysFromNow(20),
+ },
+];
+
+export const seedEmergencyContacts: EmergencyContact[] = [
+ {
+ id: "ec_demo_1",
+ name: "Sara Abebe",
+ phone: "+251911223344",
+ relationship: "Spouse",
+ },
+ {
+ id: "ec_demo_2",
+ name: "Dr. Michael Tadesse",
+ phone: "+251911000111",
+ relationship: "Family doctor",
+ },
+];
+
+export const seedFavoriteIds = ["p1", "p7", "p14", "p16", "p39"];
+
+export const DEMO_USER = {
+ id: "u_demo_gishen",
+ name: "Kirukib Abebe",
+ phone: "+251911000000",
+ email: "kirukib@example.com",
+ points: 420,
+ tier: "silver" as const,
+ isGuest: false,
+ biometricEnabled: false,
+ avatarUri: null as string | null,
+};
diff --git a/lib/i18n.ts b/lib/i18n.ts
new file mode 100644
index 0000000..a3805b2
--- /dev/null
+++ b/lib/i18n.ts
@@ -0,0 +1,24 @@
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
+import en from "@/locales/en/common.json";
+import am from "@/locales/am/common.json";
+import { useLangStore } from "@/lib/stores/langStore";
+
+const initial = useLangStore.getState().language;
+
+void i18n.use(initReactI18next).init({
+ compatibilityJSON: "v4",
+ resources: {
+ en: { translation: en },
+ am: { translation: am },
+ },
+ lng: initial,
+ fallbackLng: "en",
+ interpolation: { escapeValue: false },
+});
+
+useLangStore.subscribe((state) => {
+ void i18n.changeLanguage(state.language);
+});
+
+export default i18n;
diff --git a/lib/notifications.ts b/lib/notifications.ts
new file mode 100644
index 0000000..101c161
--- /dev/null
+++ b/lib/notifications.ts
@@ -0,0 +1,72 @@
+import * as Notifications from "expo-notifications";
+import { Platform } from "react-native";
+
+Notifications.setNotificationHandler({
+ handleNotification: async () => ({
+ shouldShowAlert: true,
+ shouldPlaySound: true,
+ shouldSetBadge: false,
+ shouldShowBanner: true,
+ shouldShowList: true,
+ }),
+});
+
+export async function ensureNotificationPermissions() {
+ const settings = await Notifications.getPermissionsAsync();
+ if (settings.granted) return true;
+ const req = await Notifications.requestPermissionsAsync();
+ return req.granted;
+}
+
+export async function scheduleDoseReminder(opts: {
+ title: string;
+ body: string;
+ secondsFromNow: number;
+ data?: Record;
+}) {
+ await ensureNotificationPermissions();
+ return Notifications.scheduleNotificationAsync({
+ content: {
+ title: opts.title,
+ body: opts.body,
+ data: opts.data,
+ categoryIdentifier: "dose",
+ },
+ trigger: {
+ type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL,
+ seconds: Math.max(5, opts.secondsFromNow),
+ repeats: false,
+ },
+ });
+}
+
+export async function scheduleEscalationCheck(opts: {
+ title: string;
+ body: string;
+ graceSeconds: number;
+ data?: Record;
+}) {
+ await ensureNotificationPermissions();
+ return Notifications.scheduleNotificationAsync({
+ content: {
+ title: opts.title,
+ body: opts.body,
+ data: { ...opts.data, type: "escalation" },
+ },
+ trigger: {
+ type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL,
+ seconds: Math.max(10, opts.graceSeconds),
+ repeats: false,
+ },
+ });
+}
+
+export function androidChannel() {
+ if (Platform.OS === "android") {
+ return Notifications.setNotificationChannelAsync("gishen-reminders", {
+ name: "Gishen reminders",
+ importance: Notifications.AndroidImportance.HIGH,
+ });
+ }
+ return Promise.resolve();
+}
diff --git a/lib/routes.ts b/lib/routes.ts
new file mode 100644
index 0000000..960f8b8
--- /dev/null
+++ b/lib/routes.ts
@@ -0,0 +1,52 @@
+import type { Ionicons } from "@expo/vector-icons";
+
+export const routes = {
+ welcome: "/(root)/auth/welcome",
+ otp: "/(root)/auth/otp",
+ language: "/(root)/auth/language",
+ home: "/(root)/(tabs)",
+ favorites: "/(root)/(tabs)/favorites",
+ cart: "/(root)/(tabs)/cart",
+ profile: "/(root)/(tabs)/profile",
+ shop: "/(root)/(screens)/shop",
+ search: "/(root)/(screens)/search",
+ product: (id: string) => `/(root)/(screens)/product/${id}` as const,
+ branches: "/(root)/(screens)/branches",
+ checkout: "/(root)/(screens)/checkout",
+ rxScan: "/(root)/(screens)/prescription/scan",
+ rxReview: "/(root)/(screens)/prescription/review",
+ rxList: "/(root)/(screens)/prescription/list",
+ rxDetail: (id: string) => `/(root)/(screens)/prescription/${id}` as const,
+ rxCalendar: (id: string) =>
+ `/(root)/(screens)/prescription/calendar/${id}` as const,
+ family: "/(root)/(screens)/family",
+ familyInvite: "/(root)/(screens)/family/invite",
+ subscriptions: "/(root)/(screens)/subscriptions",
+ profileSwitch: "/(root)/(screens)/profiles/switch",
+ profileJoin: "/(root)/(screens)/profiles/join",
+ emergencyContacts: "/(root)/(screens)/emergency-contacts",
+ orders: "/(root)/(screens)/orders",
+ orderDetail: (id: string) => `/(root)/(screens)/orders/${id}` as const,
+ tracking: (id: string) => `/(root)/(screens)/tracking/${id}` as const,
+ loyalty: "/(root)/(screens)/loyalty",
+ about: "/(root)/(screens)/about",
+ contact: "/(root)/(screens)/contact",
+ addresses: "/(root)/(screens)/addresses",
+} as const;
+
+export type Category = {
+ id: string;
+ labelKey: string;
+ icon: keyof typeof Ionicons.glyphMap;
+};
+
+export const categories: Category[] = [
+ { id: "medicines", labelKey: "categories.medicines", icon: "medkit-outline" },
+ { id: "vitamins", labelKey: "categories.vitamins", icon: "leaf-outline" },
+ { id: "personal-care", labelKey: "categories.personalCare", icon: "sparkles-outline" },
+ { id: "diabetic", labelKey: "categories.diabetic", icon: "pulse-outline" },
+ { id: "devices", labelKey: "categories.devices", icon: "hardware-chip-outline" },
+ { id: "baby", labelKey: "categories.baby", icon: "happy-outline" },
+ { id: "first-aid", labelKey: "categories.firstAid", icon: "bandage-outline" },
+ { id: "wellness", labelKey: "categories.wellness", icon: "heart-outline" },
+];
diff --git a/lib/stores/addressStore.ts b/lib/stores/addressStore.ts
new file mode 100644
index 0000000..342ae91
--- /dev/null
+++ b/lib/stores/addressStore.ts
@@ -0,0 +1,103 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+
+export type SavedAddress = {
+ id: string;
+ label: string;
+ area: string;
+ street: string;
+ landmark?: string;
+ notes?: string;
+ isDefault: boolean;
+};
+
+type AddressState = {
+ addresses: SavedAddress[];
+ add: (a: Omit & { isDefault?: boolean }) => void;
+ update: (id: string, patch: Partial) => void;
+ remove: (id: string) => void;
+ setDefault: (id: string) => void;
+ defaultAddress: () => SavedAddress | null;
+};
+
+export const seedAddresses: SavedAddress[] = [
+ {
+ id: "addr_home",
+ label: "Home",
+ area: "Bole, Addis Ababa",
+ street: "Rwanda St, Building 12, Apt 4B",
+ landmark: "Near Edna Mall",
+ notes: "Call on arrival",
+ isDefault: true,
+ },
+ {
+ id: "addr_office",
+ label: "Office",
+ area: "Kazanchis, Addis Ababa",
+ street: "Gabon St, Yaltopia Tower, Floor 6",
+ landmark: "Opposite UNECA",
+ isDefault: false,
+ },
+];
+
+export const useAddressStore = create()(
+ persist(
+ (set, get) => ({
+ addresses: seedAddresses,
+ add: (a) => {
+ const id = `addr_${Date.now()}`;
+ const makeDefault = a.isDefault || get().addresses.length === 0;
+ set({
+ addresses: [
+ {
+ id,
+ label: a.label,
+ area: a.area,
+ street: a.street,
+ landmark: a.landmark,
+ notes: a.notes,
+ isDefault: makeDefault,
+ },
+ ...get().addresses.map((x) =>
+ makeDefault ? { ...x, isDefault: false } : x
+ ),
+ ],
+ });
+ },
+ update: (id, patch) =>
+ set({
+ addresses: get().addresses.map((a) =>
+ a.id === id ? { ...a, ...patch } : a
+ ),
+ }),
+ remove: (id) => {
+ const next = get().addresses.filter((a) => a.id !== id);
+ if (next.length && !next.some((a) => a.isDefault)) {
+ next[0] = { ...next[0], isDefault: true };
+ }
+ set({ addresses: next });
+ },
+ setDefault: (id) =>
+ set({
+ addresses: get().addresses.map((a) => ({
+ ...a,
+ isDefault: a.id === id,
+ })),
+ }),
+ defaultAddress: () =>
+ get().addresses.find((a) => a.isDefault) ?? get().addresses[0] ?? null,
+ }),
+ {
+ name: "gishen-addresses",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 1,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ return !state.addresses?.length
+ ? { ...state, addresses: seedAddresses }
+ : state;
+ },
+ }
+ )
+);
diff --git a/lib/stores/authStore.ts b/lib/stores/authStore.ts
new file mode 100644
index 0000000..826f2e3
--- /dev/null
+++ b/lib/stores/authStore.ts
@@ -0,0 +1,228 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+import { DEMO_USER } from "@/lib/data/seed";
+
+export type AuthUser = {
+ id: string;
+ name: string;
+ phone: string;
+ email?: string;
+ points: number;
+ tier: "bronze" | "silver" | "gold";
+ isGuest: boolean;
+ biometricEnabled: boolean;
+ avatarUri?: string | null;
+ referralCode?: string;
+ activeVoucher?: string | null;
+};
+
+export type PointsEntry = {
+ id: string;
+ at: string;
+ label: string;
+ delta: number;
+ balance: number;
+};
+
+type AuthState = {
+ user: AuthUser | null;
+ hasOnboarded: boolean;
+ ledger: PointsEntry[];
+ setHasOnboarded: (v: boolean) => void;
+ signIn: (payload: Partial & { phone: string; name: string }) => void;
+ signOut: () => void;
+ setBiometric: (enabled: boolean) => void;
+ setAvatar: (uri: string | null) => void;
+ updateProfile: (
+ patch: Partial>
+ ) => void;
+ addPoints: (pts: number, label?: string) => void;
+ redeemPoints: (pts: number) => boolean;
+ setActiveVoucher: (code: string | null) => void;
+ ensureDemoUser: () => void;
+};
+
+function tierFor(points: number): AuthUser["tier"] {
+ if (points >= 1000) return "gold";
+ if (points >= 300) return "silver";
+ return "bronze";
+}
+
+const seedLedger: PointsEntry[] = [
+ {
+ id: "pts_1",
+ at: new Date(Date.now() - 1000 * 60 * 60 * 24 * 20).toISOString(),
+ label: "Welcome bonus",
+ delta: 50,
+ balance: 50,
+ },
+ {
+ id: "pts_2",
+ at: new Date(Date.now() - 1000 * 60 * 60 * 24 * 12).toISOString(),
+ label: "Order reward",
+ delta: 28,
+ balance: 78,
+ },
+ {
+ id: "pts_3",
+ at: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5).toISOString(),
+ label: "Referral bonus",
+ delta: 100,
+ balance: 178,
+ },
+ {
+ id: "pts_4",
+ at: new Date(Date.now() - 1000 * 60 * 60 * 24 * 2).toISOString(),
+ label: "Order reward",
+ delta: 242,
+ balance: 420,
+ },
+];
+
+export const useAuthStore = create()(
+ persist(
+ (set, get) => ({
+ user: {
+ ...DEMO_USER,
+ email: DEMO_USER.email,
+ referralCode: "GISHEN-KIRU",
+ activeVoucher: null,
+ },
+ hasOnboarded: true,
+ ledger: seedLedger,
+ setHasOnboarded: (v) => set({ hasOnboarded: v }),
+ signIn: ({ phone, name, email, isGuest, avatarUri }) =>
+ set({
+ user: {
+ id: `u_${Date.now()}`,
+ name,
+ phone,
+ email,
+ points: isGuest ? 0 : 50,
+ tier: "bronze",
+ isGuest: !!isGuest,
+ biometricEnabled: false,
+ avatarUri: avatarUri ?? null,
+ referralCode: `GISHEN-${name.slice(0, 4).toUpperCase() || "USER"}`,
+ activeVoucher: null,
+ },
+ hasOnboarded: true,
+ ledger: isGuest
+ ? []
+ : [
+ {
+ id: `pts_${Date.now()}`,
+ at: new Date().toISOString(),
+ label: "Welcome bonus",
+ delta: 50,
+ balance: 50,
+ },
+ ],
+ }),
+ signOut: () => set({ user: null }),
+ setBiometric: (enabled) => {
+ const user = get().user;
+ if (!user) return;
+ set({ user: { ...user, biometricEnabled: enabled } });
+ },
+ setAvatar: (uri) => {
+ const user = get().user;
+ if (!user) return;
+ set({ user: { ...user, avatarUri: uri } });
+ },
+ updateProfile: (patch) => {
+ const user = get().user;
+ if (!user) return;
+ set({ user: { ...user, ...patch } });
+ },
+ addPoints: (pts, label = "Order reward") => {
+ const user = get().user;
+ if (!user || user.isGuest || pts === 0) return;
+ const points = user.points + pts;
+ const entry: PointsEntry = {
+ id: `pts_${Date.now()}`,
+ at: new Date().toISOString(),
+ label,
+ delta: pts,
+ balance: points,
+ };
+ set({
+ user: { ...user, points, tier: tierFor(points) },
+ ledger: [entry, ...get().ledger],
+ });
+ },
+ redeemPoints: (pts) => {
+ const user = get().user;
+ if (!user || user.isGuest || user.points < pts) return false;
+ const points = user.points - pts;
+ const entry: PointsEntry = {
+ id: `pts_${Date.now()}`,
+ at: new Date().toISOString(),
+ label: `Redeemed for voucher`,
+ delta: -pts,
+ balance: points,
+ };
+ set({
+ user: {
+ ...user,
+ points,
+ tier: tierFor(points),
+ activeVoucher: "GISHEN10",
+ },
+ ledger: [entry, ...get().ledger],
+ });
+ return true;
+ },
+ setActiveVoucher: (code) => {
+ const user = get().user;
+ if (!user) return;
+ set({ user: { ...user, activeVoucher: code } });
+ },
+ ensureDemoUser: () => {
+ if (!get().user) {
+ set({
+ user: {
+ ...DEMO_USER,
+ referralCode: "GISHEN-KIRU",
+ activeVoucher: null,
+ },
+ hasOnboarded: true,
+ ledger: seedLedger,
+ });
+ }
+ },
+ }),
+ {
+ name: "gishen-auth",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 3,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ if (!state.user) {
+ return {
+ ...state,
+ user: {
+ ...DEMO_USER,
+ referralCode: "GISHEN-KIRU",
+ activeVoucher: null,
+ },
+ hasOnboarded: true,
+ ledger: seedLedger,
+ };
+ }
+ return {
+ ...state,
+ user: {
+ ...DEMO_USER,
+ ...state.user,
+ avatarUri: state.user.avatarUri ?? null,
+ referralCode: state.user.referralCode ?? "GISHEN-KIRU",
+ activeVoucher: state.user.activeVoucher ?? null,
+ },
+ ledger: state.ledger?.length ? state.ledger : seedLedger,
+ };
+ },
+ }
+ )
+);
diff --git a/lib/stores/cartStore.ts b/lib/stores/cartStore.ts
new file mode 100644
index 0000000..de98e3b
--- /dev/null
+++ b/lib/stores/cartStore.ts
@@ -0,0 +1,80 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+import type { Product } from "@/lib/data/products";
+
+export type CartItem = {
+ productId: string;
+ slug: string;
+ name: string;
+ price: number;
+ image: string;
+ unit: string;
+ quantity: number;
+ requiresPrescription?: boolean;
+};
+
+type CartState = {
+ items: CartItem[];
+ voucherCode: string | null;
+ addProduct: (product: Product, qty?: number) => void;
+ removeItem: (productId: string) => void;
+ setQuantity: (productId: string, quantity: number) => void;
+ clear: () => void;
+ setVoucher: (code: string | null) => void;
+ totalItems: () => number;
+ subtotal: () => number;
+};
+
+export const useCartStore = create()(
+ persist(
+ (set, get) => ({
+ items: [],
+ voucherCode: null,
+ addProduct: (product, qty = 1) => {
+ const items = [...get().items];
+ const idx = items.findIndex((i) => i.productId === product.id);
+ if (idx >= 0) {
+ items[idx] = {
+ ...items[idx],
+ quantity: items[idx].quantity + qty,
+ };
+ } else {
+ items.push({
+ productId: product.id,
+ slug: product.slug,
+ name: product.name,
+ price: product.price,
+ image: product.image,
+ unit: product.unit,
+ quantity: qty,
+ requiresPrescription: product.requiresPrescription,
+ });
+ }
+ set({ items });
+ },
+ removeItem: (productId) =>
+ set({ items: get().items.filter((i) => i.productId !== productId) }),
+ setQuantity: (productId, quantity) => {
+ if (quantity <= 0) {
+ get().removeItem(productId);
+ return;
+ }
+ set({
+ items: get().items.map((i) =>
+ i.productId === productId ? { ...i, quantity } : i
+ ),
+ });
+ },
+ clear: () => set({ items: [], voucherCode: null }),
+ setVoucher: (code) => set({ voucherCode: code }),
+ totalItems: () => get().items.reduce((n, i) => n + i.quantity, 0),
+ subtotal: () =>
+ get().items.reduce((n, i) => n + i.price * i.quantity, 0),
+ }),
+ {
+ name: "gishen-cart",
+ storage: createJSONStorage(() => AsyncStorage),
+ }
+ )
+);
diff --git a/lib/stores/emergencyContactStore.ts b/lib/stores/emergencyContactStore.ts
new file mode 100644
index 0000000..560f8bd
--- /dev/null
+++ b/lib/stores/emergencyContactStore.ts
@@ -0,0 +1,54 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+import { seedEmergencyContacts } from "@/lib/data/seed";
+
+export type EmergencyContact = {
+ id: string;
+ name: string;
+ phone: string;
+ relationship: string;
+};
+
+type EcState = {
+ contacts: EmergencyContact[];
+ graceMinutesDefault: number;
+ escalationEnabled: boolean;
+ lastEscalationAt?: string;
+ add: (c: Omit) => void;
+ remove: (id: string) => void;
+ setGrace: (m: number) => void;
+ setEscalationEnabled: (v: boolean) => void;
+ markEscalated: () => void;
+};
+
+export const useEmergencyContactStore = create()(
+ persist(
+ (set, get) => ({
+ contacts: seedEmergencyContacts,
+ graceMinutesDefault: 30,
+ escalationEnabled: true,
+ add: (c) =>
+ set({
+ contacts: [{ ...c, id: `ec_${Date.now()}` }, ...get().contacts],
+ }),
+ remove: (id) =>
+ set({ contacts: get().contacts.filter((c) => c.id !== id) }),
+ setGrace: (m) => set({ graceMinutesDefault: m }),
+ setEscalationEnabled: (v) => set({ escalationEnabled: v }),
+ markEscalated: () =>
+ set({ lastEscalationAt: new Date().toISOString() }),
+ }),
+ {
+ name: "gishen-emergency",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 2,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ return !state.contacts?.length
+ ? { ...state, contacts: seedEmergencyContacts }
+ : state;
+ },
+ }
+ )
+);
diff --git a/lib/stores/familyStore.ts b/lib/stores/familyStore.ts
new file mode 100644
index 0000000..1d7bd7e
--- /dev/null
+++ b/lib/stores/familyStore.ts
@@ -0,0 +1,67 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+import { seedFamily } from "@/lib/data/seed";
+
+export type FamilyMember = {
+ id: string;
+ name: string;
+ relationship: "spouse" | "child" | "parent" | "other";
+ phone?: string;
+ status: "pending" | "accepted";
+};
+
+type FamilyState = {
+ members: FamilyMember[];
+ activeMemberId: string | null;
+ inviteCode: string;
+ addMember: (m: Omit) => void;
+ acceptInvite: (id: string) => void;
+ removeMember: (id: string) => void;
+ setActiveMember: (id: string | null) => void;
+};
+
+export const useFamilyStore = create()(
+ persist(
+ (set, get) => ({
+ members: seedFamily,
+ activeMemberId: "fam_demo_sara",
+ inviteCode: "FAM-GISHEN",
+ addMember: (m) =>
+ set({
+ members: [
+ {
+ ...m,
+ id: `fam_${Date.now()}`,
+ status: "pending",
+ },
+ ...get().members,
+ ],
+ }),
+ acceptInvite: (id) =>
+ set({
+ members: get().members.map((m) =>
+ m.id === id ? { ...m, status: "accepted" } : m
+ ),
+ }),
+ removeMember: (id) =>
+ set({
+ members: get().members.filter((m) => m.id !== id),
+ activeMemberId:
+ get().activeMemberId === id ? null : get().activeMemberId,
+ }),
+ setActiveMember: (id) => set({ activeMemberId: id }),
+ }),
+ {
+ name: "gishen-family",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 2,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ return !state.members?.length
+ ? { ...state, members: seedFamily, activeMemberId: "fam_demo_sara" }
+ : state;
+ },
+ }
+ )
+);
diff --git a/lib/stores/favoritesStore.ts b/lib/stores/favoritesStore.ts
new file mode 100644
index 0000000..3ec80be
--- /dev/null
+++ b/lib/stores/favoritesStore.ts
@@ -0,0 +1,34 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+import { seedFavoriteIds } from "@/lib/data/seed";
+
+type FavState = {
+ ids: string[];
+ toggle: (id: string) => void;
+ has: (id: string) => boolean;
+};
+
+export const useFavoritesStore = create()(
+ persist(
+ (set, get) => ({
+ ids: seedFavoriteIds,
+ toggle: (id) => {
+ const ids = get().ids;
+ set({
+ ids: ids.includes(id) ? ids.filter((x) => x !== id) : [...ids, id],
+ });
+ },
+ has: (id) => get().ids.includes(id),
+ }),
+ {
+ name: "gishen-favorites",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 2,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ return !state.ids?.length ? { ...state, ids: seedFavoriteIds } : state;
+ },
+ }
+ )
+);
diff --git a/lib/stores/langStore.ts b/lib/stores/langStore.ts
new file mode 100644
index 0000000..dafa405
--- /dev/null
+++ b/lib/stores/langStore.ts
@@ -0,0 +1,23 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+
+export type Language = "en" | "am";
+
+type LangState = {
+ language: Language;
+ setLanguage: (language: Language) => void;
+};
+
+export const useLangStore = create()(
+ persist(
+ (set) => ({
+ language: "en",
+ setLanguage: (language) => set({ language }),
+ }),
+ {
+ name: "gishen-lang",
+ storage: createJSONStorage(() => AsyncStorage),
+ }
+ )
+);
diff --git a/lib/stores/locationStore.ts b/lib/stores/locationStore.ts
new file mode 100644
index 0000000..e607e60
--- /dev/null
+++ b/lib/stores/locationStore.ts
@@ -0,0 +1,59 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+
+export type Fulfillment = "delivery" | "pickup";
+export type PaymentMethod =
+ | "chapa"
+ | "telebirr"
+ | "mpesa"
+ | "pay_at_branch";
+
+type LocationState = {
+ fulfillment: Fulfillment;
+ areaLabel: string;
+ branchId: string | null;
+ lat: number | null;
+ lng: number | null;
+ paymentPreference: PaymentMethod;
+ setFulfillment: (f: Fulfillment) => void;
+ setAreaLabel: (label: string) => void;
+ setBranchId: (id: string | null) => void;
+ setCoords: (lat: number | null, lng: number | null) => void;
+ setPaymentPreference: (m: PaymentMethod) => void;
+ allowedPayments: () => PaymentMethod[];
+};
+
+export const useLocationStore = create()(
+ persist(
+ (set, get) => ({
+ fulfillment: "delivery",
+ areaLabel: "Addis Ababa",
+ branchId: null,
+ lat: null,
+ lng: null,
+ paymentPreference: "chapa",
+ setFulfillment: (fulfillment) => {
+ const next: Partial = { fulfillment };
+ if (fulfillment === "delivery" && get().paymentPreference === "pay_at_branch") {
+ next.paymentPreference = "chapa";
+ }
+ set(next);
+ },
+ setAreaLabel: (areaLabel) => set({ areaLabel }),
+ setBranchId: (branchId) => set({ branchId }),
+ setCoords: (lat, lng) => set({ lat, lng }),
+ setPaymentPreference: (paymentPreference) => set({ paymentPreference }),
+ allowedPayments: () => {
+ const base: PaymentMethod[] = ["chapa", "telebirr", "mpesa"];
+ return get().fulfillment === "pickup"
+ ? [...base, "pay_at_branch"]
+ : base;
+ },
+ }),
+ {
+ name: "gishen-location",
+ storage: createJSONStorage(() => AsyncStorage),
+ }
+ )
+);
diff --git a/lib/stores/ordersStore.ts b/lib/stores/ordersStore.ts
new file mode 100644
index 0000000..51f227f
--- /dev/null
+++ b/lib/stores/ordersStore.ts
@@ -0,0 +1,174 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+import { seedOrders } from "@/lib/data/seed";
+import type { CartItem } from "@/lib/stores/cartStore";
+import type { Fulfillment, PaymentMethod } from "@/lib/stores/locationStore";
+
+export type OrderStatus =
+ | "requested"
+ | "confirmed"
+ | "paid"
+ | "dispatched"
+ | "delivered"
+ | "completed"
+ | "cancelled";
+
+export type Order = {
+ id: string;
+ createdAt: string;
+ items: CartItem[];
+ subtotal: number;
+ deliveryFee: number;
+ discount: number;
+ voucherCode?: string | null;
+ total: number;
+ fulfillment: Fulfillment;
+ branchId?: string | null;
+ areaLabel?: string;
+ addressId?: string | null;
+ addressLine?: string;
+ paymentMethod: PaymentMethod;
+ status: OrderStatus;
+ riderAssigned?: boolean;
+ corporateCovered?: number;
+ selfPay?: number;
+ customerName?: string;
+ customerPhone?: string;
+ notes?: string;
+ timeline?: { at: string; label: string; status: OrderStatus | "created" }[];
+};
+
+type OrdersState = {
+ orders: Order[];
+ addOrder: (
+ order: Omit & {
+ discount?: number;
+ status?: OrderStatus;
+ }
+ ) => Order;
+ updateStatus: (id: string, status: OrderStatus) => void;
+ cancelOrder: (id: string) => void;
+ getById: (id: string) => Order | undefined;
+};
+
+function timelineFor(status: OrderStatus, createdAt: string) {
+ const steps: Order["timeline"] = [
+ { at: createdAt, label: "Order placed", status: "created" },
+ ];
+ const add = (label: string, s: OrderStatus, hours: number) => {
+ const d = new Date(createdAt);
+ d.setHours(d.getHours() + hours);
+ steps!.push({ at: d.toISOString(), label, status: s });
+ };
+ if (["confirmed", "paid", "dispatched", "delivered", "completed"].includes(status)) {
+ add("Confirmed by pharmacy", "confirmed", 0.2);
+ }
+ if (["paid", "dispatched", "delivered", "completed"].includes(status) && status !== "confirmed") {
+ add("Payment received", "paid", 0.4);
+ }
+ if (["dispatched", "delivered", "completed"].includes(status)) {
+ add("Out for delivery / ready for pickup", "dispatched", 1);
+ }
+ if (["delivered", "completed"].includes(status)) {
+ add("Delivered / collected", "delivered", 3);
+ }
+ if (status === "cancelled") {
+ steps.push({
+ at: new Date().toISOString(),
+ label: "Order cancelled",
+ status: "cancelled",
+ });
+ }
+ return steps;
+}
+
+export const useOrdersStore = create()(
+ persist(
+ (set, get) => ({
+ orders: seedOrders.map((o) => ({
+ ...o,
+ discount: o.discount ?? 0,
+ customerName: o.customerName ?? "Kirukib Abebe",
+ customerPhone: o.customerPhone ?? "+251911000000",
+ notes: o.notes ?? "",
+ timeline: o.timeline ?? timelineFor(o.status, o.createdAt),
+ })),
+ addOrder: (payload) => {
+ const createdAt = new Date().toISOString();
+ const discount = payload.discount ?? 0;
+ const status =
+ payload.status ??
+ (payload.paymentMethod === "pay_at_branch" ? "confirmed" : "paid");
+ const order: Order = {
+ ...payload,
+ discount,
+ id: `ord_${Date.now()}`,
+ createdAt,
+ status,
+ riderAssigned: false,
+ timeline: timelineFor(status, createdAt),
+ };
+ set({ orders: [order, ...get().orders] });
+ return order;
+ },
+ updateStatus: (id, status) =>
+ set({
+ orders: get().orders.map((o) => {
+ if (o.id !== id) return o;
+ const next = {
+ ...o,
+ status,
+ riderAssigned:
+ status === "dispatched" || status === "delivered"
+ ? true
+ : o.riderAssigned,
+ };
+ const stamp = new Date().toISOString();
+ const label =
+ status === "dispatched"
+ ? "Rider assigned / ready"
+ : status === "delivered"
+ ? "Delivered / collected"
+ : status === "cancelled"
+ ? "Order cancelled"
+ : `Status: ${status}`;
+ return {
+ ...next,
+ timeline: [...(o.timeline ?? []), { at: stamp, label, status }],
+ };
+ }),
+ }),
+ cancelOrder: (id) => get().updateStatus(id, "cancelled"),
+ getById: (id) => get().orders.find((o) => o.id === id),
+ }),
+ {
+ name: "gishen-orders",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 3,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ if (!state.orders?.length) {
+ return {
+ ...state,
+ orders: seedOrders.map((o) => ({
+ ...o,
+ discount: 0,
+ customerName: "Kirukib Abebe",
+ customerPhone: "+251911000000",
+ timeline: timelineFor(o.status, o.createdAt),
+ })),
+ };
+ }
+ return {
+ ...state,
+ orders: state.orders.map((o) => ({
+ ...o,
+ discount: o.discount ?? 0,
+ timeline: o.timeline ?? timelineFor(o.status, o.createdAt),
+ })),
+ };
+ },
+ }
+ )
+);
diff --git a/lib/stores/prescriptionStore.ts b/lib/stores/prescriptionStore.ts
new file mode 100644
index 0000000..b013ac4
--- /dev/null
+++ b/lib/stores/prescriptionStore.ts
@@ -0,0 +1,165 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+import {
+ seedDoseLogs,
+ seedPrescriptions,
+ seedReminders,
+} from "@/lib/data/seed";
+
+export type RxStatus =
+ | "submitted"
+ | "under_review"
+ | "approved"
+ | "queried"
+ | "rejected"
+ | "filled";
+
+export type LineStatus = "ready" | "review" | "unavailable";
+
+export type Prescription = {
+ id: string;
+ patientName: string;
+ memberId?: string | null;
+ medicineName: string;
+ medicines: { name: string; status: LineStatus }[];
+ imageUris: string[];
+ daysSupply: number;
+ lastFilledAt: string | null;
+ status: RxStatus;
+ notes?: string;
+ createdAt: string;
+};
+
+export type Reminder = {
+ id: string;
+ prescriptionId: string;
+ medicineName: string;
+ times: string[];
+ daysOfWeek: number[];
+ graceMinutes: number;
+ escalateOnMiss: boolean;
+ memberId?: string | null;
+ enabled: boolean;
+};
+
+export type DoseLog = {
+ id: string;
+ reminderId: string;
+ scheduledAt: string;
+ status: "pending" | "taken" | "snoozed" | "missed_escalated";
+ confirmedAt?: string;
+};
+
+type RxState = {
+ prescriptions: Prescription[];
+ reminders: Reminder[];
+ doseLogs: DoseLog[];
+ draftImages: string[];
+ setDraftImages: (uris: string[]) => void;
+ addPrescription: (
+ p: Omit
+ ) => Prescription;
+ updateRxStatus: (id: string, status: RxStatus) => void;
+ markRefilled: (id: string) => void;
+ removePrescription: (id: string) => void;
+ upsertReminder: (r: Omit & { id?: string }) => void;
+ removeReminder: (id: string) => void;
+ confirmDose: (logId: string) => void;
+ escalateDose: (logId: string) => void;
+ schedulePendingDose: (reminderId: string) => DoseLog;
+};
+
+export const usePrescriptionStore = create()(
+ persist(
+ (set, get) => ({
+ prescriptions: seedPrescriptions,
+ reminders: seedReminders,
+ doseLogs: seedDoseLogs,
+ draftImages: [],
+ setDraftImages: (uris) => set({ draftImages: uris }),
+ addPrescription: (payload) => {
+ const rx: Prescription = {
+ ...payload,
+ id: `rx_${Date.now()}`,
+ createdAt: new Date().toISOString(),
+ status: "submitted",
+ };
+ set({ prescriptions: [rx, ...get().prescriptions] });
+ return rx;
+ },
+ updateRxStatus: (id, status) =>
+ set({
+ prescriptions: get().prescriptions.map((p) =>
+ p.id === id ? { ...p, status } : p
+ ),
+ }),
+ markRefilled: (id) =>
+ set({
+ prescriptions: get().prescriptions.map((p) =>
+ p.id === id
+ ? { ...p, lastFilledAt: new Date().toISOString(), status: "filled" }
+ : p
+ ),
+ }),
+ removePrescription: (id) =>
+ set({
+ prescriptions: get().prescriptions.filter((p) => p.id !== id),
+ reminders: get().reminders.filter((r) => r.prescriptionId !== id),
+ }),
+ upsertReminder: (r) => {
+ const id = r.id ?? `rem_${Date.now()}`;
+ const next = { ...r, id } as Reminder;
+ const others = get().reminders.filter((x) => x.id !== id);
+ set({ reminders: [next, ...others] });
+ },
+ removeReminder: (id) =>
+ set({ reminders: get().reminders.filter((r) => r.id !== id) }),
+ confirmDose: (logId) =>
+ set({
+ doseLogs: get().doseLogs.map((l) =>
+ l.id === logId
+ ? {
+ ...l,
+ status: "taken",
+ confirmedAt: new Date().toISOString(),
+ }
+ : l
+ ),
+ }),
+ escalateDose: (logId) =>
+ set({
+ doseLogs: get().doseLogs.map((l) =>
+ l.id === logId ? { ...l, status: "missed_escalated" } : l
+ ),
+ }),
+ schedulePendingDose: (reminderId) => {
+ const log: DoseLog = {
+ id: `dose_${Date.now()}`,
+ reminderId,
+ scheduledAt: new Date().toISOString(),
+ status: "pending",
+ };
+ set({ doseLogs: [log, ...get().doseLogs] });
+ return log;
+ },
+ }),
+ {
+ name: "gishen-prescriptions",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 2,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ const empty = !state.prescriptions?.length;
+ return empty
+ ? {
+ ...state,
+ prescriptions: seedPrescriptions,
+ reminders: seedReminders,
+ doseLogs: seedDoseLogs,
+ }
+ : state;
+ },
+ }
+ )
+);
diff --git a/lib/stores/profileModeStore.ts b/lib/stores/profileModeStore.ts
new file mode 100644
index 0000000..694a227
--- /dev/null
+++ b/lib/stores/profileModeStore.ts
@@ -0,0 +1,109 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+
+export type ProfileMode = "personal" | "corporate";
+
+export type OrgMembership = {
+ orgId: string;
+ orgName: string;
+ planName: string;
+ remainingAllowance: number;
+ monthlyCap: number;
+};
+
+type ProfileState = {
+ mode: ProfileMode;
+ memberships: OrgMembership[];
+ activeOrgId: string | null;
+ setMode: (mode: ProfileMode) => void;
+ setActiveOrg: (orgId: string | null) => void;
+ joinOrg: (code: string) => { ok: boolean; message: string };
+ activeMembership: () => OrgMembership | null;
+ quoteSplit: (subtotal: number) => { covered: number; selfPay: number };
+ consumeAllowance: (amount: number) => void;
+};
+
+const DEMO_ORGS: Record = {
+ "GISHEN-BANK": {
+ orgId: "org_bank",
+ orgName: "Demo Bank Ethiopia",
+ planName: "Staff",
+ remainingAllowance: 2500,
+ monthlyCap: 5000,
+ },
+ "GISHEN-NGO": {
+ orgId: "org_ngo",
+ orgName: "Demo NGO",
+ planName: "Standard",
+ remainingAllowance: 1200,
+ monthlyCap: 3000,
+ },
+};
+
+const seededMembership = { ...DEMO_ORGS["GISHEN-BANK"] };
+
+export const useProfileModeStore = create()(
+ persist(
+ (set, get) => ({
+ mode: "personal",
+ memberships: [seededMembership],
+ activeOrgId: null,
+ setMode: (mode) => set({ mode }),
+ setActiveOrg: (orgId) =>
+ set({ activeOrgId: orgId, mode: orgId ? "corporate" : "personal" }),
+ joinOrg: (code) => {
+ const key = code.trim().toUpperCase();
+ const org = DEMO_ORGS[key];
+ if (!org) return { ok: false, message: "Invalid join code" };
+ const memberships = get().memberships;
+ if (memberships.some((m) => m.orgId === org.orgId)) {
+ set({ activeOrgId: org.orgId, mode: "corporate" });
+ return { ok: true, message: "Already a member — switched to org" };
+ }
+ set({
+ memberships: [...memberships, { ...org }],
+ activeOrgId: org.orgId,
+ mode: "corporate",
+ });
+ return { ok: true, message: `Joined ${org.orgName}` };
+ },
+ activeMembership: () => {
+ const { activeOrgId, memberships, mode } = get();
+ if (mode !== "corporate" || !activeOrgId) return null;
+ return memberships.find((m) => m.orgId === activeOrgId) ?? null;
+ },
+ quoteSplit: (subtotal) => {
+ const m = get().activeMembership();
+ if (!m) return { covered: 0, selfPay: subtotal };
+ const covered = Math.min(subtotal, m.remainingAllowance);
+ return { covered, selfPay: Math.max(0, subtotal - covered) };
+ },
+ consumeAllowance: (amount) => {
+ const { activeOrgId, memberships } = get();
+ if (!activeOrgId || amount <= 0) return;
+ set({
+ memberships: memberships.map((m) =>
+ m.orgId === activeOrgId
+ ? {
+ ...m,
+ remainingAllowance: Math.max(0, m.remainingAllowance - amount),
+ }
+ : m
+ ),
+ });
+ },
+ }),
+ {
+ name: "gishen-profile-mode",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 2,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ return !state.memberships?.length
+ ? { ...state, memberships: [seededMembership] }
+ : state;
+ },
+ }
+ )
+);
diff --git a/lib/stores/subscriptionStore.ts b/lib/stores/subscriptionStore.ts
new file mode 100644
index 0000000..78602e8
--- /dev/null
+++ b/lib/stores/subscriptionStore.ts
@@ -0,0 +1,91 @@
+import AsyncStorage from "@react-native-async-storage/async-storage";
+import { create } from "zustand";
+import { createJSONStorage, persist } from "zustand/middleware";
+import { seedSubscriptions } from "@/lib/data/seed";
+import type { Fulfillment, PaymentMethod } from "@/lib/stores/locationStore";
+
+export type SubscriptionStatus = "active" | "paused" | "cancelled";
+
+export type RefillSubscription = {
+ id: string;
+ productId: string;
+ productName: string;
+ quantity: number;
+ frequencyDays: number;
+ fulfillment: Fulfillment;
+ paymentMethod: PaymentMethod;
+ memberId?: string | null;
+ status: SubscriptionStatus;
+ nextFulfillmentAt: string;
+};
+
+type SubState = {
+ items: RefillSubscription[];
+ add: (
+ s: Omit
+ ) => void;
+ pause: (id: string) => void;
+ resume: (id: string) => void;
+ cancel: (id: string) => void;
+};
+
+function nextDate(days: number) {
+ const d = new Date();
+ d.setDate(d.getDate() + days);
+ return d.toISOString();
+}
+
+export const useSubscriptionStore = create()(
+ persist(
+ (set, get) => ({
+ items: seedSubscriptions,
+ add: (s) =>
+ set({
+ items: [
+ {
+ ...s,
+ id: `sub_${Date.now()}`,
+ status: "active",
+ nextFulfillmentAt: nextDate(s.frequencyDays),
+ },
+ ...get().items,
+ ],
+ }),
+ pause: (id) =>
+ set({
+ items: get().items.map((i) =>
+ i.id === id ? { ...i, status: "paused" } : i
+ ),
+ }),
+ resume: (id) =>
+ set({
+ items: get().items.map((i) =>
+ i.id === id
+ ? {
+ ...i,
+ status: "active",
+ nextFulfillmentAt: nextDate(i.frequencyDays),
+ }
+ : i
+ ),
+ }),
+ cancel: (id) =>
+ set({
+ items: get().items.map((i) =>
+ i.id === id ? { ...i, status: "cancelled" } : i
+ ),
+ }),
+ }),
+ {
+ name: "gishen-subscriptions",
+ storage: createJSONStorage(() => AsyncStorage),
+ version: 2,
+ migrate: (persisted: unknown) => {
+ const state = (persisted ?? {}) as Partial;
+ return !state.items?.length
+ ? { ...state, items: seedSubscriptions }
+ : state;
+ },
+ }
+ )
+);
diff --git a/lib/theme.ts b/lib/theme.ts
new file mode 100644
index 0000000..0cdef43
--- /dev/null
+++ b/lib/theme.ts
@@ -0,0 +1,168 @@
+import { Platform } from "react-native";
+
+/**
+ * Gishen design tokens.
+ *
+ * Brand lime is used as a *fill* with ink text (high contrast, distinctive).
+ * `brandText` is the accessible green reserved for green-on-white text.
+ */
+const palette = {
+ lime50: "#F6FAEC",
+ lime100: "#ECF4D8",
+ lime200: "#D9E9B2",
+ lime300: "#C3DB86",
+ lime400: "#A8C73A",
+ lime500: "#93B22E",
+ lime600: "#748E22",
+ lime700: "#55681B",
+
+ ink900: "#101410",
+ ink700: "#2C332B",
+ ink500: "#5B6157",
+ ink300: "#8A9188",
+ ink100: "#C3C8BE",
+
+ paper: "#F7F8F5",
+ white: "#FFFFFF",
+ hairline: "#E9ECE2",
+ wash: "#F1F3EC",
+
+ red500: "#D64545",
+ red50: "#FDF0F0",
+ amber500: "#E0870F",
+ amber50: "#FDF5E7",
+ blue500: "#2F6FED",
+ blue50: "#EEF3FE",
+} as const;
+
+export const colors = {
+ brand: palette.lime400,
+ brandDeep: palette.lime500,
+ brandText: palette.lime600,
+ brandSoft: palette.lime100,
+ brandWash: palette.lime50,
+ brandBorder: palette.lime200,
+
+ ink: palette.ink900,
+ inkDeep: palette.ink900,
+ inkSecondary: palette.ink500,
+ muted: palette.ink500,
+ subtle: palette.ink300,
+ disabled: palette.ink100,
+
+ page: palette.paper,
+ surface: palette.white,
+ surfaceAlt: palette.wash,
+ line: palette.hairline,
+
+ danger: palette.red500,
+ dangerSoft: palette.red50,
+ warn: palette.amber500,
+ warnSoft: palette.amber50,
+ accent: palette.amber500,
+ info: palette.blue500,
+ infoSoft: palette.blue50,
+
+ inStock: palette.lime600,
+ outOfStock: palette.red500,
+ star: "#F5A524",
+} as const;
+
+export const space = {
+ xs: 4,
+ sm: 8,
+ md: 12,
+ lg: 16,
+ xl: 20,
+ "2xl": 24,
+ "3xl": 32,
+ "4xl": 40,
+} as const;
+
+export const radii = {
+ xs: 8,
+ sm: 12,
+ md: 16,
+ lg: 20,
+ xl: 24,
+ card: 20,
+ pill: 999,
+} as const;
+
+/** Screen gutter used by every page so content lines up across the app. */
+export const gutter = 20;
+
+export const fonts = {
+ regular: "Jakarta_400Regular",
+ medium: "Jakarta_500Medium",
+ semibold: "Jakarta_600SemiBold",
+ bold: "Jakarta_700Bold",
+ extrabold: "Jakarta_800ExtraBold",
+} as const;
+
+export type TypeVariant =
+ | "display"
+ | "h1"
+ | "h2"
+ | "h3"
+ | "body"
+ | "bodyMedium"
+ | "bodySm"
+ | "label"
+ | "caption"
+ | "micro"
+ | "price"
+ | "priceLg";
+
+export const typography: Record<
+ TypeVariant,
+ { fontFamily: string; fontSize: number; lineHeight: number; letterSpacing?: number }
+> = {
+ display: { fontFamily: fonts.extrabold, fontSize: 30, lineHeight: 36, letterSpacing: -0.6 },
+ h1: { fontFamily: fonts.extrabold, fontSize: 24, lineHeight: 30, letterSpacing: -0.4 },
+ h2: { fontFamily: fonts.bold, fontSize: 18, lineHeight: 24, letterSpacing: -0.2 },
+ h3: { fontFamily: fonts.semibold, fontSize: 15, lineHeight: 20, letterSpacing: -0.1 },
+ body: { fontFamily: fonts.regular, fontSize: 14, lineHeight: 21 },
+ bodyMedium: { fontFamily: fonts.medium, fontSize: 14, lineHeight: 20 },
+ bodySm: { fontFamily: fonts.regular, fontSize: 13, lineHeight: 19 },
+ label: { fontFamily: fonts.semibold, fontSize: 13, lineHeight: 17 },
+ caption: { fontFamily: fonts.medium, fontSize: 12, lineHeight: 16 },
+ micro: { fontFamily: fonts.semibold, fontSize: 11, lineHeight: 14, letterSpacing: 0.2 },
+ price: { fontFamily: fonts.bold, fontSize: 16, lineHeight: 21, letterSpacing: -0.2 },
+ priceLg: { fontFamily: fonts.extrabold, fontSize: 24, lineHeight: 29, letterSpacing: -0.5 },
+};
+
+type Shadow = {
+ shadowColor: string;
+ shadowOpacity: number;
+ shadowRadius: number;
+ shadowOffset: { width: number; height: number };
+ elevation: number;
+};
+
+const shadow = (opacity: number, radius: number, y: number, elevation: number): Shadow => ({
+ shadowColor: "#16240A",
+ shadowOpacity: Platform.OS === "android" ? opacity * 1.4 : opacity,
+ shadowRadius: radius,
+ shadowOffset: { width: 0, height: y },
+ elevation,
+});
+
+export const shadows = {
+ /** Resting cards. Nearly invisible, just lifts off the page. */
+ xs: shadow(0.04, 6, 2, 1),
+ sm: shadow(0.05, 10, 4, 2),
+ /** Sheets, floating tab bar, sticky bars. */
+ md: shadow(0.08, 18, 8, 8),
+ lg: shadow(0.12, 28, 14, 16),
+} as const;
+
+/** Card recipe reused across screens so every surface matches. */
+export const card = {
+ backgroundColor: colors.surface,
+ borderRadius: radii.card,
+ borderWidth: 1,
+ borderColor: colors.line,
+} as const;
+
+export const hitSlop = { top: 10, bottom: 10, left: 10, right: 10 } as const;
diff --git a/lib/utils.ts b/lib/utils.ts
new file mode 100644
index 0000000..78af0c8
--- /dev/null
+++ b/lib/utils.ts
@@ -0,0 +1,11 @@
+export function formatETB(amount: number): string {
+ return `${amount.toLocaleString("en-ET")} ETB`;
+}
+
+export function cn(...parts: Array): string {
+ return parts.filter(Boolean).join(" ");
+}
+
+export const CALL_PHONE = "+251930099850";
+export const WHATSAPP_NUMBER = "251930099850";
+export const CHATWOOT_BASE = "https://chat.yaltopia.com";
diff --git a/locales/am/common.json b/locales/am/common.json
new file mode 100644
index 0000000..0ff345f
--- /dev/null
+++ b/locales/am/common.json
@@ -0,0 +1,84 @@
+{
+ "common": {
+ "appName": "ጊሸን ፋርማሲ",
+ "tagline": "ጤናዎ ወደ በርዎ ይደርሳል",
+ "continue": "ቀጥል",
+ "getStarted": "ጀምር",
+ "save": "አስቀምጥ",
+ "cancel": "ሰርዝ",
+ "seeAll": "ሁሉንም ይመልከቱ",
+ "search": "እዚህ ይፈልጉ...",
+ "scan": "ቅኝት",
+ "home": "መነሻ",
+ "favorites": "ተወዳጆች",
+ "cart": "ጋሪ",
+ "profile": "መገለጫ",
+ "shop": "ሱቅ",
+ "branches": "ቅርንጫፎች",
+ "orders": "ትዕዛዞች",
+ "loyalty": "ነጥቦች",
+ "about": "ስለ እኛ",
+ "contact": "አግኙን",
+ "language": "ቋንቋ",
+ "call": "ደውሉ",
+ "whatsapp": "ዋትስአፕ",
+ "chat": "ቀጥታ ውይይት",
+ "addProduct": "+ ምርት ጨምር",
+ "payNow": "አሁን ክፈል",
+ "checkout": "ክፍያ",
+ "delivery": "ማድረስ",
+ "pickup": "መውሰድ",
+ "total": "ድምር",
+ "payment": "ክፍያ",
+ "useVoucher": "+ ቫውቸር ተጠቀም",
+ "trustedTitle": "የታመነው",
+ "trustedSubtitle": "የመስመር ላይ ፋርማሲ",
+ "bestProducts": "ምርጥ ምርቶች",
+ "categories": "ምድቦች",
+ "personal": "ግል",
+ "corporate": "ድርጅት",
+ "taken": "ተወስዷል",
+ "snooze": "አራዝም",
+ "emergencyContacts": "የአደጋ ጊዜ እውቂያዎች",
+ "family": "ቤተሰብ",
+ "subscriptions": "ደንበኝነት ምዝገባዎች",
+ "prescriptions": "የሐኪም ትዕዛዞች",
+ "switchProfile": "መገለጫ ቀይር",
+ "joinOrg": "ድርጅት ተቀላቀል",
+ "payAtBranch": "በቅርንጫፍ ክፈል",
+ "chapa": "ቻፓ",
+ "telebirr": "ቴሌብር",
+ "mpesa": "ኤም-ፔሳ",
+ "emptyCart": "ጋሪዎ ባዶ ነው",
+ "emptyFavorites": "ተወዳጆች የሉም",
+ "refillDue": "መሙላት ተቃርቧል",
+ "contactNotified": "የአደጋ ጊዜ እውቂያ ተነግሯል",
+ "guest": "እንደ እንግዳ ቀጥል",
+ "signIn": "ግባ",
+ "otpHint": "ወደ ስልክዎ የተላከውን ኮድ ያስገቡ",
+ "sendOtp": "ኮድ ላክ",
+ "verify": "አረጋግጥ",
+ "enableBiometric": "ባዮሜትሪክ ክፈት አንቃ",
+ "nearestBranch": "ቅርብ ቅርንጫፎች",
+ "useLocation": "አካባቢዬን ተጠቀም",
+ "addresses": "አድራሻዎች",
+ "rewards": "ሽልማቶች",
+ "referral": "የማጣቀሻ ኮድ",
+ "inviteFamily": "ቤተሰብ ጋብዝ",
+ "manageSubs": "ደንበኝነት አስተዳድር",
+ "scanRx": "የሐኪም ትዕዛዝ ቅኝት",
+ "calendarReminders": "የቀን መቁጠሪያ ማስታወሻዎች",
+ "graceMinutes": "የጥበቃ ደቂቃዎች",
+ "escalation": "መድሃኒት ካልተረጋገጠ የአደጋ ጊዜ እውቂያን አሳውቅ"
+ },
+ "categories": {
+ "medicines": "መድሃኒት",
+ "vitamins": "ቫይታሚን",
+ "personalCare": "ጤና",
+ "diabetic": "ስኳር",
+ "devices": "መሳሪያዎች",
+ "baby": "ሕፃን",
+ "firstAid": "የመጀመሪያ እርዳታ",
+ "wellness": "ጤናማ ሕይወት"
+ }
+}
diff --git a/locales/en/common.json b/locales/en/common.json
new file mode 100644
index 0000000..48209fd
--- /dev/null
+++ b/locales/en/common.json
@@ -0,0 +1,84 @@
+{
+ "common": {
+ "appName": "Gishen Pharmacy",
+ "tagline": "Healthcare delivered to your doorstep",
+ "continue": "Continue",
+ "getStarted": "Get started",
+ "save": "Save",
+ "cancel": "Cancel",
+ "seeAll": "See all",
+ "search": "Search here...",
+ "scan": "Scan",
+ "home": "Home",
+ "favorites": "Favorites",
+ "cart": "Cart",
+ "profile": "Profile",
+ "shop": "Shop",
+ "branches": "Branches",
+ "orders": "Orders",
+ "loyalty": "Loyalty",
+ "about": "About",
+ "contact": "Contact",
+ "language": "Language",
+ "call": "Call",
+ "whatsapp": "WhatsApp",
+ "chat": "Live chat",
+ "addProduct": "+ Add product",
+ "payNow": "Pay Now",
+ "checkout": "Checkout",
+ "delivery": "Delivery",
+ "pickup": "Pickup",
+ "total": "Total",
+ "payment": "Payment",
+ "useVoucher": "+ Use voucher",
+ "trustedTitle": "Your Trusted",
+ "trustedSubtitle": "Online Pharmacy",
+ "bestProducts": "Best Products",
+ "categories": "Categories",
+ "personal": "Personal",
+ "corporate": "Corporate",
+ "taken": "Taken",
+ "snooze": "Snooze",
+ "emergencyContacts": "Emergency contacts",
+ "family": "Family",
+ "subscriptions": "Subscriptions",
+ "prescriptions": "Prescriptions",
+ "switchProfile": "Switch profile",
+ "joinOrg": "Join organisation",
+ "payAtBranch": "Pay at branch",
+ "chapa": "Chapa",
+ "telebirr": "Telebirr",
+ "mpesa": "M-Pesa",
+ "emptyCart": "Your cart is empty",
+ "emptyFavorites": "No favorites yet",
+ "refillDue": "Refill due soon",
+ "contactNotified": "Emergency contact notified",
+ "guest": "Continue as guest",
+ "signIn": "Sign in",
+ "otpHint": "Enter the code sent to your phone",
+ "sendOtp": "Send code",
+ "verify": "Verify",
+ "enableBiometric": "Enable biometric unlock",
+ "nearestBranch": "Nearest branches",
+ "useLocation": "Use my location",
+ "addresses": "Addresses",
+ "rewards": "Rewards",
+ "referral": "Referral code",
+ "inviteFamily": "Invite family",
+ "manageSubs": "Manage subscriptions",
+ "scanRx": "Scan prescription",
+ "calendarReminders": "Calendar reminders",
+ "graceMinutes": "Grace minutes",
+ "escalation": "Notify emergency contact if dose not confirmed"
+ },
+ "categories": {
+ "medicines": "Medicine",
+ "vitamins": "Vitamin",
+ "personalCare": "Health",
+ "diabetic": "Diabetic",
+ "devices": "Devices",
+ "baby": "Baby",
+ "firstAid": "First Aid",
+ "wellness": "Wellness"
+ }
+}
diff --git a/metro.config.js b/metro.config.js
new file mode 100644
index 0000000..89c5426
--- /dev/null
+++ b/metro.config.js
@@ -0,0 +1,6 @@
+const { getDefaultConfig } = require("expo/metro-config");
+const { withNativeWind } = require("nativewind/metro");
+
+const config = getDefaultConfig(__dirname);
+
+module.exports = withNativeWind(config, { input: "./app/global.css" });
diff --git a/nativewind-env.d.ts b/nativewind-env.d.ts
new file mode 100644
index 0000000..a13e313
--- /dev/null
+++ b/nativewind-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..1a169c9
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,10409 @@
+{
+ "name": "gishen-mob",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "gishen-mob",
+ "version": "1.0.0",
+ "dependencies": {
+ "@expo-google-fonts/plus-jakarta-sans": "^0.4.2",
+ "@expo/vector-icons": "^14.1.0",
+ "@react-native-async-storage/async-storage": "2.1.2",
+ "expo": "~53.0.0",
+ "expo-camera": "~16.1.11",
+ "expo-constants": "~17.1.7",
+ "expo-font": "~13.3.1",
+ "expo-image-picker": "~16.1.4",
+ "expo-linking": "~7.1.7",
+ "expo-local-authentication": "~16.0.5",
+ "expo-location": "~18.1.6",
+ "expo-notifications": "~0.31.4",
+ "expo-router": "~5.1.6",
+ "expo-splash-screen": "~0.30.10",
+ "expo-status-bar": "~2.2.3",
+ "i18next": "^25.7.2",
+ "lucide-react-native": "^0.511.0",
+ "nativewind": "4.1.23",
+ "react": "19.0.0",
+ "react-dom": "19.0.0",
+ "react-i18next": "^16.5.0",
+ "react-native": "0.79.6",
+ "react-native-gesture-handler": "~2.24.0",
+ "react-native-maps": "1.20.1",
+ "react-native-reanimated": "~3.17.4",
+ "react-native-safe-area-context": "5.4.0",
+ "react-native-screens": "~4.11.1",
+ "react-native-svg": "15.11.2",
+ "react-native-web": "^0.20.0",
+ "tailwindcss": "^3.4.17",
+ "zustand": "^5.0.3"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.26.0",
+ "@types/react": "~19.0.10",
+ "typescript": "~5.8.3"
+ }
+ },
+ "node_modules/@0no-co/graphql.web": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.3.3.tgz",
+ "integrity": "sha512-4gFGBdyaFmQ6n9euhp5JtIGS4ZeivwDr1tCPENUxTvy5wyv532yOtFCr9zzYAJh1s6uibgC+TRXUcay+mxzCoQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
+ },
+ "peerDependenciesMeta": {
+ "graphql": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
+ "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.8",
+ "@babel/types": "^7.29.8",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz",
+ "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz",
+ "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-member-expression-to-functions": "^7.29.7",
+ "@babel/helper-optimise-call-expression": "^7.29.7",
+ "@babel/helper-replace-supers": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-regexp-features-plugin": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz",
+ "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "regexpu-core": "^6.3.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-define-polyfill-provider": {
+ "version": "0.6.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz",
+ "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-plugin-utils": "^7.28.6",
+ "debug": "^4.4.3",
+ "lodash.debounce": "^4.0.8",
+ "resolve": "^1.22.11"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz",
+ "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz",
+ "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-remap-async-to-generator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz",
+ "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-wrap-function": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz",
+ "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.29.7",
+ "@babel/helper-optimise-call-expression": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz",
+ "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-wrap-function": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz",
+ "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz",
+ "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "chalk": "^2.4.2",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
+ "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
+ "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.8"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-decorators": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz",
+ "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/plugin-syntax-decorators": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-export-default-from": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.29.7.tgz",
+ "integrity": "sha512-p+G5BNXDcy3bOXplhY4HybQ1GxH3i2Tppmdm/3epyRu2VgJJZuUlZ61MqRTg582Q7ZLBdP7fePYvsumSEkMxcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-async-generators": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+ "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-bigint": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+ "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-class-properties": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+ "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.12.13"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-class-static-block": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
+ "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-decorators": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz",
+ "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-dynamic-import": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
+ "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-export-default-from": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.29.7.tgz",
+ "integrity": "sha512-foag0BB37ROhdeIX9O8G0jX7hw0UekJc04cHMrYLOnrErsnBKqJGHJ8eDRpoCFZBvEPPygmmtw4qyU97qa4oOw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-flow": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.29.7.tgz",
+ "integrity": "sha512-ajMX6QPcyomotqwpzhkYGxcK2i/us0rs1Qo9QvUpa+Fca0FTmqrzKrctoIYLMxcOhGZldGT/BAVkRGTWBiR8gQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-attributes": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz",
+ "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-meta": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+ "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-json-strings": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+ "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz",
+ "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+ "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+ "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-numeric-separator": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+ "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+ "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+ "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-optional-chaining": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+ "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-private-property-in-object": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
+ "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-top-level-await": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+ "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz",
+ "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-arrow-functions": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz",
+ "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-generator-functions": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz",
+ "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-remap-async-to-generator": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-to-generator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz",
+ "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-remap-async-to-generator": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoping": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz",
+ "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-properties": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz",
+ "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-classes": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz",
+ "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-replace-supers": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-computed-properties": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz",
+ "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/template": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-destructuring": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz",
+ "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-export-namespace-from": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz",
+ "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-flow-strip-types": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.29.7.tgz",
+ "integrity": "sha512-wRHeUjUjCZnMHmiO5bRgjFLcoEh7JyTdByOW11ahhwNa4V0bmeGEaIvt51yq0zQp2yWIpqfxXXPyUP6GFJZHOQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/plugin-syntax-flow": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-for-of": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz",
+ "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-function-name": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz",
+ "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-literals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz",
+ "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-logical-assignment-operators": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz",
+ "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-commonjs": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz",
+ "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz",
+ "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz",
+ "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-numeric-separator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz",
+ "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-rest-spread": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz",
+ "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/plugin-transform-destructuring": "^7.29.7",
+ "@babel/plugin-transform-parameters": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-catch-binding": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz",
+ "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-chaining": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz",
+ "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-parameters": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz",
+ "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-methods": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz",
+ "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-property-in-object": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz",
+ "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-create-class-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-display-name": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz",
+ "integrity": "sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz",
+ "integrity": "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/plugin-syntax-jsx": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-development": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz",
+ "integrity": "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-transform-react-jsx": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz",
+ "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz",
+ "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-pure-annotations": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz",
+ "integrity": "sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regenerator": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.8.tgz",
+ "integrity": "sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-runtime": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.7.tgz",
+ "integrity": "sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "babel-plugin-polyfill-corejs2": "^0.4.14",
+ "babel-plugin-polyfill-corejs3": "^0.13.0",
+ "babel-plugin-polyfill-regenerator": "^0.6.5",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-shorthand-properties": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz",
+ "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-spread": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.8.tgz",
+ "integrity": "sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-sticky-regex": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz",
+ "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-template-literals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz",
+ "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typescript": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz",
+ "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-create-class-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7",
+ "@babel/plugin-syntax-typescript": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-regex": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz",
+ "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/preset-react": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.29.7.tgz",
+ "integrity": "sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "@babel/plugin-transform-react-display-name": "^7.29.7",
+ "@babel/plugin-transform-react-jsx": "^7.29.7",
+ "@babel/plugin-transform-react-jsx-development": "^7.29.7",
+ "@babel/plugin-transform-react-pure-annotations": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/preset-typescript": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz",
+ "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "@babel/plugin-syntax-jsx": "^7.29.7",
+ "@babel/plugin-transform-modules-commonjs": "^7.29.7",
+ "@babel/plugin-transform-typescript": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
+ "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
+ "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.8",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.8",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.8",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse--for-generate-function-map": {
+ "name": "@babel/traverse",
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
+ "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.8",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.8",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.8",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
+ "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@egjs/hammerjs": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
+ "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hammerjs": "^2.0.36"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@expo-google-fonts/plus-jakarta-sans": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@expo-google-fonts/plus-jakarta-sans/-/plus-jakarta-sans-0.4.2.tgz",
+ "integrity": "sha512-6LYVmVGwjQvH+uzzWlVc9+oMj4lkNQ41aymVDjO+x8aFk8kCye20wOyLomYMZaMezA++Uf1mZRCw3W3Fy/hxEA==",
+ "license": "MIT AND OFL-1.1"
+ },
+ "node_modules/@expo/cli": {
+ "version": "0.24.24",
+ "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.24.24.tgz",
+ "integrity": "sha512-XybHfF2QNPJNnHoUKHcG796iEkX5126UuTAs6MSpZuvZRRQRj/sGCLX+driCOVHbDOpcCOusMuHrhxHbtTApyg==",
+ "license": "MIT",
+ "dependencies": {
+ "@0no-co/graphql.web": "^1.0.8",
+ "@babel/runtime": "^7.20.0",
+ "@expo/code-signing-certificates": "^0.0.6",
+ "@expo/config": "~11.0.13",
+ "@expo/config-plugins": "~10.1.2",
+ "@expo/devcert": "^1.1.2",
+ "@expo/env": "~1.0.7",
+ "@expo/image-utils": "^0.7.6",
+ "@expo/json-file": "^9.1.5",
+ "@expo/metro-config": "~0.20.18",
+ "@expo/osascript": "^2.2.5",
+ "@expo/package-manager": "^1.8.6",
+ "@expo/plist": "^0.3.5",
+ "@expo/prebuild-config": "^9.0.12",
+ "@expo/schema-utils": "^0.1.0",
+ "@expo/spawn-async": "^1.7.2",
+ "@expo/ws-tunnel": "^1.0.1",
+ "@expo/xcpretty": "^4.3.0",
+ "@react-native/dev-middleware": "0.79.6",
+ "@urql/core": "^5.0.6",
+ "@urql/exchange-retry": "^1.3.0",
+ "accepts": "^1.3.8",
+ "arg": "^5.0.2",
+ "better-opn": "~3.0.2",
+ "bplist-creator": "0.1.0",
+ "bplist-parser": "^0.3.1",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.3.0",
+ "compression": "^1.7.4",
+ "connect": "^3.7.0",
+ "debug": "^4.3.4",
+ "env-editor": "^0.4.1",
+ "freeport-async": "^2.0.0",
+ "getenv": "^2.0.0",
+ "glob": "^10.4.2",
+ "lan-network": "^0.1.6",
+ "minimatch": "^9.0.0",
+ "node-forge": "^1.3.3",
+ "npm-package-arg": "^11.0.0",
+ "ora": "^3.4.0",
+ "picomatch": "^3.0.1",
+ "pretty-bytes": "^5.6.0",
+ "pretty-format": "^29.7.0",
+ "progress": "^2.0.3",
+ "prompts": "^2.3.2",
+ "qrcode-terminal": "0.11.0",
+ "require-from-string": "^2.0.2",
+ "requireg": "^0.2.2",
+ "resolve": "^1.22.2",
+ "resolve-from": "^5.0.0",
+ "resolve.exports": "^2.0.3",
+ "semver": "^7.6.0",
+ "send": "^0.19.0",
+ "slugify": "^1.3.4",
+ "source-map-support": "~0.5.21",
+ "stacktrace-parser": "^0.1.10",
+ "structured-headers": "^0.4.1",
+ "tar": "^7.4.3",
+ "terminal-link": "^2.1.1",
+ "undici": "^6.18.2",
+ "wrap-ansi": "^7.0.0",
+ "ws": "^8.12.1"
+ },
+ "bin": {
+ "expo-internal": "build/bin/cli"
+ }
+ },
+ "node_modules/@expo/cli/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@expo/code-signing-certificates": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@expo/code-signing-certificates/-/code-signing-certificates-0.0.6.tgz",
+ "integrity": "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==",
+ "license": "MIT",
+ "dependencies": {
+ "node-forge": "^1.3.3"
+ }
+ },
+ "node_modules/@expo/config": {
+ "version": "11.0.13",
+ "resolved": "https://registry.npmjs.org/@expo/config/-/config-11.0.13.tgz",
+ "integrity": "sha512-TnGb4u/zUZetpav9sx/3fWK71oCPaOjZHoVED9NaEncktAd0Eonhq5NUghiJmkUGt3gGSjRAEBXiBbbY9/B1LA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "~7.10.4",
+ "@expo/config-plugins": "~10.1.2",
+ "@expo/config-types": "^53.0.5",
+ "@expo/json-file": "^9.1.5",
+ "deepmerge": "^4.3.1",
+ "getenv": "^2.0.0",
+ "glob": "^10.4.2",
+ "require-from-string": "^2.0.2",
+ "resolve-from": "^5.0.0",
+ "resolve-workspace-root": "^2.0.0",
+ "semver": "^7.6.0",
+ "slugify": "^1.3.4",
+ "sucrase": "3.35.0"
+ }
+ },
+ "node_modules/@expo/config-plugins": {
+ "version": "10.1.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-10.1.2.tgz",
+ "integrity": "sha512-IMYCxBOcnuFStuK0Ay+FzEIBKrwW8OVUMc65+v0+i7YFIIe8aL342l7T4F8lR4oCfhXn7d6M5QPgXvjtc/gAcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/config-types": "^53.0.5",
+ "@expo/json-file": "~9.1.5",
+ "@expo/plist": "^0.3.5",
+ "@expo/sdk-runtime-versions": "^1.0.0",
+ "chalk": "^4.1.2",
+ "debug": "^4.3.5",
+ "getenv": "^2.0.0",
+ "glob": "^10.4.2",
+ "resolve-from": "^5.0.0",
+ "semver": "^7.5.4",
+ "slash": "^3.0.0",
+ "slugify": "^1.6.6",
+ "xcode": "^3.0.1",
+ "xml2js": "0.6.0"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@expo/config-types": {
+ "version": "53.0.5",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-53.0.5.tgz",
+ "integrity": "sha512-kqZ0w44E+HEGBjy+Lpyn0BVL5UANg/tmNixxaRMLS6nf37YsDrLk2VMAmeKMMk5CKG0NmOdVv3ngeUjRQMsy9g==",
+ "license": "MIT"
+ },
+ "node_modules/@expo/config/node_modules/@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/@expo/config/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@expo/devcert": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.1.tgz",
+ "integrity": "sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/sudo-prompt": "^9.3.1",
+ "debug": "^3.1.0"
+ }
+ },
+ "node_modules/@expo/devcert/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/@expo/env": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@expo/env/-/env-1.0.7.tgz",
+ "integrity": "sha512-qSTEnwvuYJ3umapO9XJtrb1fAqiPlmUUg78N0IZXXGwQRt+bkp0OBls+Y5Mxw/Owj8waAM0Z3huKKskRADR5ow==",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "debug": "^4.3.4",
+ "dotenv": "~16.4.5",
+ "dotenv-expand": "~11.0.6",
+ "getenv": "^2.0.0"
+ }
+ },
+ "node_modules/@expo/fingerprint": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.13.4.tgz",
+ "integrity": "sha512-MYfPYBTMfrrNr07DALuLhG6EaLVNVrY/PXjEzsjWdWE4ZFn0yqI0IdHNkJG7t1gePT8iztHc7qnsx+oo/rDo6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/spawn-async": "^1.7.2",
+ "arg": "^5.0.2",
+ "chalk": "^4.1.2",
+ "debug": "^4.3.4",
+ "find-up": "^5.0.0",
+ "getenv": "^2.0.0",
+ "glob": "^10.4.2",
+ "ignore": "^5.3.1",
+ "minimatch": "^9.0.0",
+ "p-limit": "^3.1.0",
+ "resolve-from": "^5.0.0",
+ "semver": "^7.6.0"
+ },
+ "bin": {
+ "fingerprint": "bin/cli.js"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@expo/image-utils": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.7.6.tgz",
+ "integrity": "sha512-GKnMqC79+mo/1AFrmAcUcGfbsXXTRqOMNS1umebuevl3aaw+ztsYEFEiuNhHZW7PQ3Xs3URNT513ZxKhznDscw==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/spawn-async": "^1.7.2",
+ "chalk": "^4.0.0",
+ "getenv": "^2.0.0",
+ "jimp-compact": "0.16.1",
+ "parse-png": "^2.1.0",
+ "resolve-from": "^5.0.0",
+ "semver": "^7.6.0",
+ "temp-dir": "~2.0.0",
+ "unique-string": "~2.0.0"
+ }
+ },
+ "node_modules/@expo/image-utils/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@expo/json-file": {
+ "version": "9.1.5",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-9.1.5.tgz",
+ "integrity": "sha512-prWBhLUlmcQtvN6Y7BpW2k9zXGd3ySa3R6rAguMJkp1z22nunLN64KYTUWfijFlprFoxm9r2VNnGkcbndAlgKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "~7.10.4",
+ "json5": "^2.2.3"
+ }
+ },
+ "node_modules/@expo/json-file/node_modules/@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/@expo/metro-config": {
+ "version": "0.20.18",
+ "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.20.18.tgz",
+ "integrity": "sha512-qPYq3Cq61KQO1CppqtmxA1NGKpzFOmdiL7WxwLhEVnz73LPSgneW7dV/3RZwVFkjThzjA41qB4a9pxDqtpepPg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.5",
+ "@babel/parser": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "@expo/config": "~11.0.13",
+ "@expo/env": "~1.0.7",
+ "@expo/json-file": "~9.1.5",
+ "@expo/spawn-async": "^1.7.2",
+ "chalk": "^4.1.0",
+ "debug": "^4.3.2",
+ "dotenv": "~16.4.5",
+ "dotenv-expand": "~11.0.6",
+ "getenv": "^2.0.0",
+ "glob": "^10.4.2",
+ "jsc-safe-url": "^0.2.4",
+ "lightningcss": "~1.27.0",
+ "minimatch": "^9.0.0",
+ "postcss": "~8.4.32",
+ "resolve-from": "^5.0.0"
+ }
+ },
+ "node_modules/@expo/metro-runtime": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-5.0.5.tgz",
+ "integrity": "sha512-P8UFTi+YsmiD1BmdTdiIQITzDMcZgronsA3RTQ4QKJjHM3bas11oGzLQOnFaIZnlEV8Rrr3m1m+RHxvnpL+t/A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react-native": "*"
+ }
+ },
+ "node_modules/@expo/osascript": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.7.1.tgz",
+ "integrity": "sha512-Zn03EX6In7ts2lPUW2ESUSkEhEWQN1qqsiXjadtZMJOuZRkMiAg1ZQHuvz9DjByDWNJ2pBwAGyrts9lj9k389g==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/spawn-async": "^1.8.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@expo/package-manager": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.13.1.tgz",
+ "integrity": "sha512-y/K+CaYYpZpNGZhSX4HyLT/vyIunFjNfyoxNysPBCefeLKI/VCx6f9LNPzrxayr3rCYO5bl9O8H+HRQK265Nkg==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/json-file": "^11.0.1",
+ "@expo/spawn-async": "^1.8.0",
+ "chalk": "^4.0.0",
+ "npm-package-arg": "^11.0.0",
+ "ora": "^3.4.0",
+ "resolve-workspace-root": "^2.0.0"
+ }
+ },
+ "node_modules/@expo/package-manager/node_modules/@expo/json-file": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz",
+ "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.20.0",
+ "json5": "^2.2.3"
+ }
+ },
+ "node_modules/@expo/plist": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.3.5.tgz",
+ "integrity": "sha512-9RYVU1iGyCJ7vWfg3e7c/NVyMFs8wbl+dMWZphtFtsqyN9zppGREU3ctlD3i8KUE0sCUTVnLjCWr+VeUIDep2g==",
+ "license": "MIT",
+ "dependencies": {
+ "@xmldom/xmldom": "^0.8.8",
+ "base64-js": "^1.2.3",
+ "xmlbuilder": "^15.1.1"
+ }
+ },
+ "node_modules/@expo/prebuild-config": {
+ "version": "9.0.12",
+ "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-9.0.12.tgz",
+ "integrity": "sha512-AKH5Scf+gEMgGxZZaimrJI2wlUJlRoqzDNn7/rkhZa5gUTnO4l6slKak2YdaH+nXlOWCNfAQWa76NnpQIfmv6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/config": "~11.0.13",
+ "@expo/config-plugins": "~10.1.2",
+ "@expo/config-types": "^53.0.5",
+ "@expo/image-utils": "^0.7.6",
+ "@expo/json-file": "^9.1.5",
+ "@react-native/normalize-colors": "0.79.6",
+ "debug": "^4.3.1",
+ "resolve-from": "^5.0.0",
+ "semver": "^7.6.0",
+ "xml2js": "0.6.0"
+ }
+ },
+ "node_modules/@expo/prebuild-config/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@expo/schema-utils": {
+ "version": "0.1.9",
+ "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-0.1.9.tgz",
+ "integrity": "sha512-t9bYwG4Z0yCVzHYJoDMci1OFq2FkBkhStlfUGSkspKYTwB/84+x6sY+CXCgdhkQNQtvWaugW5KUs9YZfAXq9Sg==",
+ "license": "MIT"
+ },
+ "node_modules/@expo/sdk-runtime-versions": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz",
+ "integrity": "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==",
+ "license": "MIT"
+ },
+ "node_modules/@expo/server": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/@expo/server/-/server-0.6.3.tgz",
+ "integrity": "sha512-Ea7NJn9Xk1fe4YeJ86rObHSv/bm3u/6WiQPXEqXJ2GrfYpVab2Swoh9/PnSM3KjR64JAgKjArDn1HiPjITCfHA==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "debug": "^4.3.4",
+ "source-map-support": "~0.5.21",
+ "undici": "^6.18.2 || ^7.0.0"
+ }
+ },
+ "node_modules/@expo/spawn-async": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz",
+ "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==",
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.6"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@expo/sudo-prompt": {
+ "version": "9.3.2",
+ "resolved": "https://registry.npmjs.org/@expo/sudo-prompt/-/sudo-prompt-9.3.2.tgz",
+ "integrity": "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==",
+ "license": "MIT"
+ },
+ "node_modules/@expo/vector-icons": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-14.1.0.tgz",
+ "integrity": "sha512-7T09UE9h8QDTsUeMGymB4i+iqvtEeaO5VvUjryFB4tugDTG/bkzViWA74hm5pfjjDEhYMXWaX112mcvhccmIwQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo-font": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/@expo/ws-tunnel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-1.0.6.tgz",
+ "integrity": "sha512-nDRbLmSrJar7abvUjp3smDwH8HcbZcoOEa5jVPUv9/9CajgmWw20JNRwTuBRzWIWIkEJDkz20GoNA+tSwUqk0Q==",
+ "license": "MIT"
+ },
+ "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==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/code-frame": "^7.20.0",
+ "chalk": "^4.1.0",
+ "js-yaml": "^4.1.0"
+ },
+ "bin": {
+ "excpretty": "build/cli.js"
+ }
+ },
+ "node_modules/@ide/backoff": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@ide/backoff/-/backoff-1.0.0.tgz",
+ "integrity": "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==",
+ "license": "MIT"
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@isaacs/ttlcache": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz",
+ "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+ "license": "ISC",
+ "dependencies": {
+ "camelcase": "^5.3.1",
+ "find-up": "^4.1.0",
+ "get-package-type": "^0.1.0",
+ "js-yaml": "^3.13.1",
+ "resolve-from": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz",
+ "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/schema": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz",
+ "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/create-cache-key-function": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz",
+ "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/environment": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
+ "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-mock": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/fake-timers": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
+ "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@sinonjs/fake-timers": "^10.0.2",
+ "@types/node": "*",
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "license": "MIT",
+ "dependencies": {
+ "@sinclair/typebox": "^0.27.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/transform": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
+ "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@jest/types": "^29.6.3",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "babel-plugin-istanbul": "^6.1.1",
+ "chalk": "^4.0.0",
+ "convert-source-map": "^2.0.0",
+ "fast-json-stable-stringify": "^2.1.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "pirates": "^4.0.4",
+ "slash": "^3.0.0",
+ "write-file-atomic": "^4.0.2"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/types": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "@types/istanbul-reports": "^3.0.0",
+ "@types/node": "*",
+ "@types/yargs": "^17.0.8",
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+ "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz",
+ "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-native-async-storage/async-storage": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.1.2.tgz",
+ "integrity": "sha512-dvlNq4AlGWC+ehtH12p65+17V0Dx7IecOWl6WanF2ja38O1Dcjjvn7jVzkUHJ5oWkQBlyASurTPlTHgKXyYiow==",
+ "license": "MIT",
+ "dependencies": {
+ "merge-options": "^3.0.4"
+ },
+ "peerDependencies": {
+ "react-native": "^0.0.0-0 || >=0.65 <1.0"
+ }
+ },
+ "node_modules/@react-native/assets-registry": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.6.tgz",
+ "integrity": "sha512-UVSP1224PWg0X+mRlZNftV5xQwZGfawhivuW8fGgxNK9MS/U84xZ+16lkqcPh1ank6MOt239lIWHQ1S33CHgqA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/babel-plugin-codegen": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.79.6.tgz",
+ "integrity": "sha512-CS5OrgcMPixOyUJ/Sk/HSsKsKgyKT5P7y3CojimOQzWqRZBmoQfxdST4ugj7n1H+ebM2IKqbgovApFbqXsoX0g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.25.3",
+ "@react-native/codegen": "0.79.6"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/babel-preset": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.79.6.tgz",
+ "integrity": "sha512-H+FRO+r2Ql6b5IwfE0E7D52JhkxjeGSBSUpCXAI5zQ60zSBJ54Hwh2bBJOohXWl4J+C7gKYSAd2JHMUETu+c/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.25.2",
+ "@babel/plugin-proposal-export-default-from": "^7.24.7",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.3",
+ "@babel/plugin-syntax-export-default-from": "^7.24.7",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+ "@babel/plugin-transform-arrow-functions": "^7.24.7",
+ "@babel/plugin-transform-async-generator-functions": "^7.25.4",
+ "@babel/plugin-transform-async-to-generator": "^7.24.7",
+ "@babel/plugin-transform-block-scoping": "^7.25.0",
+ "@babel/plugin-transform-class-properties": "^7.25.4",
+ "@babel/plugin-transform-classes": "^7.25.4",
+ "@babel/plugin-transform-computed-properties": "^7.24.7",
+ "@babel/plugin-transform-destructuring": "^7.24.8",
+ "@babel/plugin-transform-flow-strip-types": "^7.25.2",
+ "@babel/plugin-transform-for-of": "^7.24.7",
+ "@babel/plugin-transform-function-name": "^7.25.1",
+ "@babel/plugin-transform-literals": "^7.25.2",
+ "@babel/plugin-transform-logical-assignment-operators": "^7.24.7",
+ "@babel/plugin-transform-modules-commonjs": "^7.24.8",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7",
+ "@babel/plugin-transform-numeric-separator": "^7.24.7",
+ "@babel/plugin-transform-object-rest-spread": "^7.24.7",
+ "@babel/plugin-transform-optional-catch-binding": "^7.24.7",
+ "@babel/plugin-transform-optional-chaining": "^7.24.8",
+ "@babel/plugin-transform-parameters": "^7.24.7",
+ "@babel/plugin-transform-private-methods": "^7.24.7",
+ "@babel/plugin-transform-private-property-in-object": "^7.24.7",
+ "@babel/plugin-transform-react-display-name": "^7.24.7",
+ "@babel/plugin-transform-react-jsx": "^7.25.2",
+ "@babel/plugin-transform-react-jsx-self": "^7.24.7",
+ "@babel/plugin-transform-react-jsx-source": "^7.24.7",
+ "@babel/plugin-transform-regenerator": "^7.24.7",
+ "@babel/plugin-transform-runtime": "^7.24.7",
+ "@babel/plugin-transform-shorthand-properties": "^7.24.7",
+ "@babel/plugin-transform-spread": "^7.24.7",
+ "@babel/plugin-transform-sticky-regex": "^7.24.7",
+ "@babel/plugin-transform-typescript": "^7.25.2",
+ "@babel/plugin-transform-unicode-regex": "^7.24.7",
+ "@babel/template": "^7.25.0",
+ "@react-native/babel-plugin-codegen": "0.79.6",
+ "babel-plugin-syntax-hermes-parser": "0.25.1",
+ "babel-plugin-transform-flow-enums": "^0.0.2",
+ "react-refresh": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@babel/core": "*"
+ }
+ },
+ "node_modules/@react-native/codegen": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.79.6.tgz",
+ "integrity": "sha512-iRBX8Lgbqypwnfba7s6opeUwVyaR23mowh9ILw7EcT2oLz3RqMmjJdrbVpWhGSMGq2qkPfqAH7bhO8C7O+xfjQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.25.2",
+ "@babel/parser": "^7.25.3",
+ "glob": "^7.1.1",
+ "hermes-parser": "0.25.1",
+ "invariant": "^2.2.4",
+ "nullthrows": "^1.1.1",
+ "yargs": "^17.6.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@babel/core": "*"
+ }
+ },
+ "node_modules/@react-native/codegen/node_modules/brace-expansion": {
+ "version": "1.1.18",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
+ "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@react-native/codegen/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@react-native/codegen/node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.79.6.tgz",
+ "integrity": "sha512-ZHVst9vByGsegeaddkD2YbZ6NvYb4n3pD9H7Pit94u+NlByq2uBJghoOjT6EKqg+UVl8tLRdi88cU2pDPwdHqA==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-native/dev-middleware": "0.79.6",
+ "chalk": "^4.0.0",
+ "debug": "^2.2.0",
+ "invariant": "^2.2.4",
+ "metro": "^0.82.0",
+ "metro-config": "^0.82.0",
+ "metro-core": "^0.82.0",
+ "semver": "^7.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@react-native-community/cli": "*"
+ },
+ "peerDependenciesMeta": {
+ "@react-native-community/cli": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@react-native/debugger-frontend": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.79.6.tgz",
+ "integrity": "sha512-lIK/KkaH7ueM22bLO0YNaQwZbT/oeqhaghOvmZacaNVbJR1Cdh/XAqjT8FgCS+7PUnbxA8B55NYNKGZG3O2pYw==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/dev-middleware": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.79.6.tgz",
+ "integrity": "sha512-BK3GZBa9c7XSNR27EDRtxrgyyA3/mf1j3/y+mPk7Ac0Myu85YNrXnC9g3mL5Ytwo0g58TKrAIgs1fF2Q5Mn6mQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@isaacs/ttlcache": "^1.4.1",
+ "@react-native/debugger-frontend": "0.79.6",
+ "chrome-launcher": "^0.15.2",
+ "chromium-edge-launcher": "^0.2.0",
+ "connect": "^3.6.5",
+ "debug": "^2.2.0",
+ "invariant": "^2.2.4",
+ "nullthrows": "^1.1.1",
+ "open": "^7.0.3",
+ "serve-static": "^1.16.2",
+ "ws": "^6.2.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/dev-middleware/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/@react-native/dev-middleware/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/@react-native/dev-middleware/node_modules/ws": {
+ "version": "6.2.6",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.6.tgz",
+ "integrity": "sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA==",
+ "license": "MIT",
+ "dependencies": {
+ "async-limiter": "~1.0.0"
+ }
+ },
+ "node_modules/@react-native/gradle-plugin": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.79.6.tgz",
+ "integrity": "sha512-C5odetI6py3CSELeZEVz+i00M+OJuFZXYnjVD4JyvpLn462GesHRh+Se8mSkU5QSaz9cnpMnyFLJAx05dokWbA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/js-polyfills": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.79.6.tgz",
+ "integrity": "sha512-6wOaBh1namYj9JlCNgX2ILeGUIwc6OP6MWe3Y5jge7Xz9fVpRqWQk88Q5Y9VrAtTMTcxoX3CvhrfRr3tGtSfQw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/normalize-colors": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.79.6.tgz",
+ "integrity": "sha512-0v2/ruY7eeKun4BeKu+GcfO+SHBdl0LJn4ZFzTzjHdWES0Cn+ONqKljYaIv8p9MV2Hx/kcdEvbY4lWI34jC/mQ==",
+ "license": "MIT"
+ },
+ "node_modules/@react-native/virtualized-lists": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.79.6.tgz",
+ "integrity": "sha512-khA/Hrbb+rB68YUHrLubfLgMOD9up0glJhw25UE3Kntj32YDyuO0Tqc81ryNTcCekFKJ8XrAaEjcfPg81zBGPw==",
+ "license": "MIT",
+ "dependencies": {
+ "invariant": "^2.2.4",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/react": "^19.0.0",
+ "react": "*",
+ "react-native": "*"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-navigation/bottom-tabs": {
+ "version": "7.18.15",
+ "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.18.15.tgz",
+ "integrity": "sha512-R1NtTQOeI69NtcQQONXDDW8NDUhtXJSF5izJ+NMJyfYMUdnd/DpbS4QMP0qLsrLSNkHxBNISuu3B+drsSxi7aQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.9.37",
+ "color": "^4.2.3",
+ "sf-symbols-typescript": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.3.15",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
+ }
+ },
+ "node_modules/@react-navigation/core": {
+ "version": "7.21.11",
+ "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.21.11.tgz",
+ "integrity": "sha512-bCW1PsLA/eOXDOukcJFEzlcL3Zpy8DJuDCfkDDwAQlAgoSZ/J9+ZeDRUMmCUi6xbnFgvFEEIMertaLeErOFP0Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/routers": "^7.6.4",
+ "escape-string-regexp": "^4.0.0",
+ "fast-deep-equal": "^3.1.3",
+ "nanoid": "^3.3.11",
+ "query-string": "^7.1.3",
+ "react-is": "^19.1.0",
+ "use-latest-callback": "^0.2.4",
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "react": ">= 18.2.0"
+ }
+ },
+ "node_modules/@react-navigation/elements": {
+ "version": "2.9.37",
+ "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.37.tgz",
+ "integrity": "sha512-M67E3ca9xTvx121SacdK/IN/HOUpZ17zAMx7nEBRQDYPMmcxlFRO9MX6xoVYcfvhZPPoLkrG/qqWUt6DUDxwMg==",
+ "license": "MIT",
+ "dependencies": {
+ "color": "^4.2.3",
+ "use-latest-callback": "^0.2.4",
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "@react-native-masked-view/masked-view": ">= 0.2.0",
+ "@react-navigation/native": "^7.3.15",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@react-native-masked-view/masked-view": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-navigation/native": {
+ "version": "7.3.15",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.3.15.tgz",
+ "integrity": "sha512-qgYZJOZ0VLJHcA2svxsPcctk4vVmw5jDW07UXNTe06pPgkwxx08aUAOzRY/HzhmcE2SK5Cw1w8i1AwoyDaiyug==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/core": "^7.21.11",
+ "escape-string-regexp": "^4.0.0",
+ "fast-deep-equal": "^3.1.3",
+ "nanoid": "^3.3.11",
+ "standard-navigation": "^0.0.8",
+ "use-latest-callback": "^0.2.4"
+ },
+ "peerDependencies": {
+ "react": ">= 18.2.0",
+ "react-native": "*"
+ }
+ },
+ "node_modules/@react-navigation/native-stack": {
+ "version": "7.18.7",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.18.7.tgz",
+ "integrity": "sha512-FXjyAKZhr7N4yMFi/abLR0I6Fe5jB2acfz1z3MlEM+QWlw5LLNpF2/25fnDOqogriYbsZglurSFx7gSdUzciZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.9.37",
+ "color": "^4.2.3",
+ "sf-symbols-typescript": "^2.1.0",
+ "warn-once": "^0.1.1"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.3.15",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
+ }
+ },
+ "node_modules/@react-navigation/routers": {
+ "version": "7.6.4",
+ "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.6.4.tgz",
+ "integrity": "sha512-GI7eJm8/KsZUQaYcXvEExikKurRZRgEsSzyZ7faENfi65yqJBCXjDMwyN1pF6pNW1MoLH1ErDwDivFxY6BzD3w==",
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11"
+ }
+ },
+ "node_modules/@sinclair/typebox": {
+ "version": "0.27.12",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz",
+ "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==",
+ "license": "MIT"
+ },
+ "node_modules/@sinonjs/commons": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
+ "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/fake-timers": {
+ "version": "10.3.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
+ "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.0"
+ }
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/geojson": {
+ "version": "7946.0.16",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/graceful-fs": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
+ "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/hammerjs": {
+ "version": "2.0.46",
+ "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz",
+ "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/istanbul-lib-coverage": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
+ "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
+ "license": "MIT"
+ },
+ "node_modules/@types/istanbul-lib-report": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
+ "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/istanbul-lib-coverage": "*"
+ }
+ },
+ "node_modules/@types/istanbul-reports": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
+ "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/istanbul-lib-report": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "26.1.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz",
+ "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~8.3.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.0.14",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.14.tgz",
+ "integrity": "sha512-ixLZ7zG7j1fM0DijL9hDArwhwcCb4vqmePgwtV0GfnkHRSCUEv4LvzarcTdhoqgyMznUx/EhoTUv31CKZzkQlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/stack-utils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
+ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/yargs": {
+ "version": "17.0.35",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz",
+ "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/yargs-parser": "*"
+ }
+ },
+ "node_modules/@types/yargs-parser": {
+ "version": "21.0.3",
+ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
+ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
+ "license": "MIT"
+ },
+ "node_modules/@urql/core": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.2.0.tgz",
+ "integrity": "sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==",
+ "license": "MIT",
+ "dependencies": {
+ "@0no-co/graphql.web": "^1.0.13",
+ "wonka": "^6.3.2"
+ }
+ },
+ "node_modules/@urql/exchange-retry": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@urql/exchange-retry/-/exchange-retry-1.3.2.tgz",
+ "integrity": "sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg==",
+ "license": "MIT",
+ "dependencies": {
+ "@urql/core": "^5.1.2",
+ "wonka": "^6.3.2"
+ },
+ "peerDependencies": {
+ "@urql/core": "^5.0.0"
+ }
+ },
+ "node_modules/@xmldom/xmldom": {
+ "version": "0.8.13",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz",
+ "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "license": "MIT",
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
+ "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/anser": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz",
+ "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==",
+ "license": "MIT"
+ },
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-escapes/node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "license": "MIT"
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/anymatch/node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "license": "MIT"
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "license": "Python-2.0"
+ },
+ "node_modules/array-timsort": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz",
+ "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==",
+ "license": "MIT"
+ },
+ "node_modules/asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
+ "license": "MIT"
+ },
+ "node_modules/assert": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz",
+ "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "is-nan": "^1.3.2",
+ "object-is": "^1.1.5",
+ "object.assign": "^4.1.4",
+ "util": "^0.12.5"
+ }
+ },
+ "node_modules/async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "license": "MIT"
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/babel-jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
+ "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/transform": "^29.7.0",
+ "@types/babel__core": "^7.1.14",
+ "babel-plugin-istanbul": "^6.1.1",
+ "babel-preset-jest": "^29.6.3",
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.8.0"
+ }
+ },
+ "node_modules/babel-plugin-istanbul": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+ "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-instrument": "^5.0.4",
+ "test-exclude": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/babel-plugin-jest-hoist": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
+ "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.3.3",
+ "@babel/types": "^7.3.3",
+ "@types/babel__core": "^7.1.14",
+ "@types/babel__traverse": "^7.0.6"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-corejs2": {
+ "version": "0.4.17",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz",
+ "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-define-polyfill-provider": "^0.6.8",
+ "semver": "^6.3.1"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-corejs3": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz",
+ "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-define-polyfill-provider": "^0.6.5",
+ "core-js-compat": "^3.43.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-regenerator": {
+ "version": "0.6.8",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz",
+ "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-define-polyfill-provider": "^0.6.8"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-react-native-web": {
+ "version": "0.19.13",
+ "resolved": "https://registry.npmjs.org/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.19.13.tgz",
+ "integrity": "sha512-4hHoto6xaN23LCyZgL9LJZc3olmAxd7b6jDzlZnKXAh4rRAbZRKNBJoOOdp46OBqgy+K0t0guTj5/mhA8inymQ==",
+ "license": "MIT"
+ },
+ "node_modules/babel-plugin-syntax-hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ==",
+ "license": "MIT",
+ "dependencies": {
+ "hermes-parser": "0.25.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-flow-enums": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz",
+ "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-syntax-flow": "^7.12.1"
+ }
+ },
+ "node_modules/babel-preset-current-node-syntax": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz",
+ "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-syntax-async-generators": "^7.8.4",
+ "@babel/plugin-syntax-bigint": "^7.8.3",
+ "@babel/plugin-syntax-class-properties": "^7.12.13",
+ "@babel/plugin-syntax-class-static-block": "^7.14.5",
+ "@babel/plugin-syntax-import-attributes": "^7.24.7",
+ "@babel/plugin-syntax-import-meta": "^7.10.4",
+ "@babel/plugin-syntax-json-strings": "^7.8.3",
+ "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+ "@babel/plugin-syntax-numeric-separator": "^7.10.4",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+ "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
+ "@babel/plugin-syntax-top-level-await": "^7.14.5"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0 || ^8.0.0-0"
+ }
+ },
+ "node_modules/babel-preset-expo": {
+ "version": "13.2.5",
+ "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-13.2.5.tgz",
+ "integrity": "sha512-YjVkP1bOLO2OgR2fyCedruYMPR7GFbAtCvvWITBW1UAp6e3ACYZtN6uoqkXgXP6PHQkb6M7qf2vZreBPEZK38A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.25.9",
+ "@babel/plugin-proposal-decorators": "^7.12.9",
+ "@babel/plugin-proposal-export-default-from": "^7.24.7",
+ "@babel/plugin-syntax-export-default-from": "^7.24.7",
+ "@babel/plugin-transform-export-namespace-from": "^7.25.9",
+ "@babel/plugin-transform-flow-strip-types": "^7.25.2",
+ "@babel/plugin-transform-modules-commonjs": "^7.24.8",
+ "@babel/plugin-transform-object-rest-spread": "^7.24.7",
+ "@babel/plugin-transform-parameters": "^7.24.7",
+ "@babel/plugin-transform-private-methods": "^7.24.7",
+ "@babel/plugin-transform-private-property-in-object": "^7.24.7",
+ "@babel/plugin-transform-runtime": "^7.24.7",
+ "@babel/preset-react": "^7.22.15",
+ "@babel/preset-typescript": "^7.23.0",
+ "@react-native/babel-preset": "0.79.6",
+ "babel-plugin-react-native-web": "~0.19.13",
+ "babel-plugin-syntax-hermes-parser": "^0.25.1",
+ "babel-plugin-transform-flow-enums": "^0.0.2",
+ "debug": "^4.3.4",
+ "react-refresh": "^0.14.2",
+ "resolve-from": "^5.0.0"
+ },
+ "peerDependencies": {
+ "babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405"
+ },
+ "peerDependenciesMeta": {
+ "babel-plugin-react-compiler": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/babel-preset-jest": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
+ "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
+ "license": "MIT",
+ "dependencies": {
+ "babel-plugin-jest-hoist": "^29.6.3",
+ "babel-preset-current-node-syntax": "^1.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/badgin": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz",
+ "integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==",
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT"
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.11.12",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz",
+ "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==",
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/better-opn": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz",
+ "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==",
+ "license": "MIT",
+ "dependencies": {
+ "open": "^8.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/better-opn/node_modules/open": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+ "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+ "license": "MIT",
+ "dependencies": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/big-integer": {
+ "version": "1.6.52",
+ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
+ "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
+ "license": "Unlicense",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "license": "ISC"
+ },
+ "node_modules/bplist-creator": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
+ "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==",
+ "license": "MIT",
+ "dependencies": {
+ "stream-buffers": "2.2.x"
+ }
+ },
+ "node_modules/bplist-parser": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz",
+ "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==",
+ "license": "MIT",
+ "dependencies": {
+ "big-integer": "1.6.x"
+ },
+ "engines": {
+ "node": ">= 5.10.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
+ "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz",
+ "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.44",
+ "caniuse-lite": "^1.0.30001806",
+ "electron-to-chromium": "^1.5.393",
+ "node-releases": "^2.0.51",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/bser": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
+ "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "node-int64": "^0.4.0"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "license": "MIT"
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
+ "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "get-intrinsic": "^1.3.0",
+ "set-function-length": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==",
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==",
+ "license": "MIT",
+ "dependencies": {
+ "caller-callsite": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001807",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001807.tgz",
+ "integrity": "sha512-daRXJ9EB/rdRgu7kV+TTl1YUKtlsMWblPl2sLnpg9DZae16QCegol6A1SmCE31Lm9mXC1sRWGt/krouH+/dl7Q==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/chrome-launcher": {
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz",
+ "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/node": "*",
+ "escape-string-regexp": "^4.0.0",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0"
+ },
+ "bin": {
+ "print-chrome-path": "bin/print-chrome-path.js"
+ },
+ "engines": {
+ "node": ">=12.13.0"
+ }
+ },
+ "node_modules/chromium-edge-launcher": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz",
+ "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/node": "*",
+ "escape-string-regexp": "^4.0.0",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0",
+ "mkdirp": "^1.0.4",
+ "rimraf": "^3.0.2"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
+ "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==",
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cli-spinners": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "license": "MIT"
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/cliui/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/cliui/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/commander": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/comment-json": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.6.2.tgz",
+ "integrity": "sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==",
+ "license": "MIT",
+ "dependencies": {
+ "array-timsort": "^1.0.3",
+ "esprima": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/compressible": {
+ "version": "2.0.18",
+ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
+ "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": ">= 1.43.0 < 2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/compression": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
+ "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "compressible": "~2.0.18",
+ "debug": "2.6.9",
+ "negotiator": "~0.6.4",
+ "on-headers": "~1.1.0",
+ "safe-buffer": "5.2.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/compression/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/compression/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/compression/node_modules/negotiator": {
+ "version": "0.6.4",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
+ "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "license": "MIT"
+ },
+ "node_modules/connect": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "finalhandler": "1.1.2",
+ "parseurl": "~1.3.3",
+ "utils-merge": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/connect/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/connect/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "license": "MIT"
+ },
+ "node_modules/core-js-compat": {
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz",
+ "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.28.7"
+ },
+ "engines": {
+ "node": ">=6.4.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
+ "node_modules/cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "license": "MIT",
+ "dependencies": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cosmiconfig/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/cosmiconfig/node_modules/js-yaml": {
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz",
+ "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/cross-fetch": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz",
+ "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "node-fetch": "^2.7.0"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/crypto-random-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/css-in-js-utils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
+ "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==",
+ "license": "MIT",
+ "dependencies": {
+ "hyphenate-style-name": "^1.0.3"
+ }
+ },
+ "node_modules/css-select": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+ "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-tree": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
+ "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.0.14",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/css-tree/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decode-uri-component": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "license": "MIT",
+ "dependencies": {
+ "clone": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "license": "Apache-2.0",
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "license": "MIT"
+ },
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.4.7",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+ "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/dotenv-expand": {
+ "version": "11.0.7",
+ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz",
+ "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dotenv": "^16.4.5"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "license": "MIT"
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.402",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.402.tgz",
+ "integrity": "sha512-/oOpMaPT6Yg+6/1XQhyIPlzgj7Ye9zf+nNM2Uh6OcE2G2oNptWazFa+qB2Pdqqbsc9KnIDzgAntoYN0dbwOXwA==",
+ "license": "ISC"
+ },
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/env-editor": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz",
+ "integrity": "sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/error-stack-parser": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
+ "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
+ "license": "MIT",
+ "dependencies": {
+ "stackframe": "^1.3.4"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+ "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/expo": {
+ "version": "53.0.27",
+ "resolved": "https://registry.npmjs.org/expo/-/expo-53.0.27.tgz",
+ "integrity": "sha512-iQwe2uWLb88opUY4vBYEW1d2GUq3lsa43gsMBEdDV+6pw0Oek93l/4nDLe0ODDdrBRjIJm/rdhKqJC/ehHCUqw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.0",
+ "@expo/cli": "0.24.24",
+ "@expo/config": "~11.0.13",
+ "@expo/config-plugins": "~10.1.2",
+ "@expo/fingerprint": "0.13.4",
+ "@expo/metro-config": "0.20.18",
+ "@expo/vector-icons": "^14.0.0",
+ "babel-preset-expo": "~13.2.5",
+ "expo-asset": "~11.1.7",
+ "expo-constants": "~17.1.8",
+ "expo-file-system": "~18.1.11",
+ "expo-font": "~13.3.2",
+ "expo-keep-awake": "~14.1.4",
+ "expo-modules-autolinking": "2.1.15",
+ "expo-modules-core": "2.5.0",
+ "react-native-edge-to-edge": "1.6.0",
+ "whatwg-url-without-unicode": "8.0.0-3"
+ },
+ "bin": {
+ "expo": "bin/cli",
+ "expo-modules-autolinking": "bin/autolinking",
+ "fingerprint": "bin/fingerprint"
+ },
+ "peerDependencies": {
+ "@expo/dom-webview": "*",
+ "@expo/metro-runtime": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-webview": "*"
+ },
+ "peerDependenciesMeta": {
+ "@expo/dom-webview": {
+ "optional": true
+ },
+ "@expo/metro-runtime": {
+ "optional": true
+ },
+ "react-native-webview": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/expo-application": {
+ "version": "6.1.5",
+ "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-6.1.5.tgz",
+ "integrity": "sha512-ToImFmzw8luY043pWFJhh2ZMm4IwxXoHXxNoGdlhD4Ym6+CCmkAvCglg0FK8dMLzAb+/XabmOE7Rbm8KZb6NZg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
+ "node_modules/expo-asset": {
+ "version": "11.1.7",
+ "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-11.1.7.tgz",
+ "integrity": "sha512-b5P8GpjUh08fRCf6m5XPVAh7ra42cQrHBIMgH2UXP+xsj4Wufl6pLy6jRF5w6U7DranUMbsXm8TOyq4EHy7ADg==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/image-utils": "^0.7.6",
+ "expo-constants": "~17.1.7"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/expo-camera": {
+ "version": "16.1.11",
+ "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-16.1.11.tgz",
+ "integrity": "sha512-etA5ZKoC6nPBnWWqiTmlX//zoFZ6cWQCCIdmpUHTGHAKd4qZNCkhPvBWbi8o32pDe57lix1V4+TPFgEcvPwsaA==",
+ "license": "MIT",
+ "dependencies": {
+ "invariant": "^2.2.4"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-web": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/expo-constants": {
+ "version": "17.1.8",
+ "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-17.1.8.tgz",
+ "integrity": "sha512-sOCeMN/BWLA7hBP6lMwoEQzFNgTopk6YY03sBAmwT216IHyL54TjNseg8CRU1IQQ/+qinJ2fYWCl7blx2TiNcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/config": "~11.0.13",
+ "@expo/env": "~1.0.7"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/expo-file-system": {
+ "version": "18.1.11",
+ "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-18.1.11.tgz",
+ "integrity": "sha512-HJw/m0nVOKeqeRjPjGdvm+zBi5/NxcdPf8M8P3G2JFvH5Z8vBWqVDic2O58jnT1OFEy0XXzoH9UqFu7cHg9DTQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/expo-font": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-13.3.2.tgz",
+ "integrity": "sha512-wUlMdpqURmQ/CNKK/+BIHkDA5nGjMqNlYmW0pJFXY/KE/OG80Qcavdu2sHsL4efAIiNGvYdBS10WztuQYU4X0A==",
+ "license": "MIT",
+ "dependencies": {
+ "fontfaceobserver": "^2.1.0"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*"
+ }
+ },
+ "node_modules/expo-image-loader": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-5.1.0.tgz",
+ "integrity": "sha512-sEBx3zDQIODWbB5JwzE7ZL5FJD+DK3LVLWBVJy6VzsqIA6nDEnSFnsnWyCfCTSvbGigMATs1lgkC2nz3Jpve1Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
+ "node_modules/expo-image-picker": {
+ "version": "16.1.4",
+ "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-16.1.4.tgz",
+ "integrity": "sha512-bTmmxtw1AohUT+HxEBn2vYwdeOrj1CLpMXKjvi9FKSoSbpcarT4xxI0z7YyGwDGHbrJqyyic3I9TTdP2J2b4YA==",
+ "license": "MIT",
+ "dependencies": {
+ "expo-image-loader": "~5.1.0"
+ },
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
+ "node_modules/expo-keep-awake": {
+ "version": "14.1.4",
+ "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-14.1.4.tgz",
+ "integrity": "sha512-wU9qOnosy4+U4z/o4h8W9PjPvcFMfZXrlUoKTMBW7F4pLqhkkP/5G4EviPZixv4XWFMjn1ExQ5rV6BX8GwJsWA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*"
+ }
+ },
+ "node_modules/expo-linking": {
+ "version": "7.1.7",
+ "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-7.1.7.tgz",
+ "integrity": "sha512-ZJaH1RIch2G/M3hx2QJdlrKbYFUTOjVVW4g39hfxrE5bPX9xhZUYXqxqQtzMNl1ylAevw9JkgEfWbBWddbZ3UA==",
+ "license": "MIT",
+ "dependencies": {
+ "expo-constants": "~17.1.7",
+ "invariant": "^2.2.4"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/expo-local-authentication": {
+ "version": "16.0.5",
+ "resolved": "https://registry.npmjs.org/expo-local-authentication/-/expo-local-authentication-16.0.5.tgz",
+ "integrity": "sha512-JzrUssLBB5tr06ffbZJC074fru2mw6He3ALtwlRnrmL7svMJS0zvm6e5Gx5CSxfHf1DgneBVBnyRlmtWxQzY9Q==",
+ "license": "MIT",
+ "dependencies": {
+ "invariant": "^2.2.4"
+ },
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
+ "node_modules/expo-location": {
+ "version": "18.1.6",
+ "resolved": "https://registry.npmjs.org/expo-location/-/expo-location-18.1.6.tgz",
+ "integrity": "sha512-l5dQQ2FYkrBgNzaZN1BvSmdhhcztFOUucu2kEfDBMV4wSIuTIt/CKsho+F3RnAiWgvui1wb1WTTf80E8zq48hA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
+ "node_modules/expo-modules-autolinking": {
+ "version": "2.1.15",
+ "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-2.1.15.tgz",
+ "integrity": "sha512-IUITUERdkgooXjr9bXsX0PmhrZUIGTMyP6NtmQpAxN5+qtf/I7ewbwLx1/rX7tgiAOzaYme+PZOp/o6yqIhFsw==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/spawn-async": "^1.7.2",
+ "chalk": "^4.1.0",
+ "commander": "^7.2.0",
+ "find-up": "^5.0.0",
+ "glob": "^10.4.2",
+ "require-from-string": "^2.0.2",
+ "resolve-from": "^5.0.0"
+ },
+ "bin": {
+ "expo-modules-autolinking": "bin/expo-modules-autolinking.js"
+ }
+ },
+ "node_modules/expo-modules-core": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-2.5.0.tgz",
+ "integrity": "sha512-aIbQxZE2vdCKsolQUl6Q9Farlf8tjh/ROR4hfN1qT7QBGPl1XrJGnaOKkcgYaGrlzCPg/7IBe0Np67GzKMZKKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "invariant": "^2.2.4"
+ }
+ },
+ "node_modules/expo-notifications": {
+ "version": "0.31.5",
+ "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.31.5.tgz",
+ "integrity": "sha512-HsitfTrSESFDWwaX0Y+6GQlWEooQqZKdGbNTwTPHfp5PNCr02tVPwwya9j1tdg3Awj8/vmfXmSxzNhULfmgJhQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/image-utils": "^0.7.6",
+ "@ide/backoff": "^1.0.0",
+ "abort-controller": "^3.0.0",
+ "assert": "^2.0.0",
+ "badgin": "^1.1.5",
+ "expo-application": "~6.1.5",
+ "expo-constants": "~17.1.8"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/expo-router": {
+ "version": "5.1.11",
+ "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-5.1.11.tgz",
+ "integrity": "sha512-6YQGqQM2rviVSiU6++hrJDPMByHZ7Oiux4XmgoSaGdaHku5QOn9911f2puEUZh2H9ALKBipw5v3ZkrECBd6Zbw==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/metro-runtime": "5.0.5",
+ "@expo/schema-utils": "^0.1.0",
+ "@expo/server": "^0.6.3",
+ "@radix-ui/react-slot": "1.2.0",
+ "@react-navigation/bottom-tabs": "^7.3.10",
+ "@react-navigation/native": "^7.1.6",
+ "@react-navigation/native-stack": "^7.3.10",
+ "client-only": "^0.0.1",
+ "invariant": "^2.2.4",
+ "react-fast-compare": "^3.2.2",
+ "react-native-is-edge-to-edge": "^1.1.6",
+ "semver": "~7.6.3",
+ "server-only": "^0.0.1",
+ "shallowequal": "^1.1.0"
+ },
+ "peerDependencies": {
+ "@react-navigation/drawer": "^7.3.9",
+ "expo": "*",
+ "expo-constants": "*",
+ "expo-linking": "*",
+ "react-native-reanimated": "*",
+ "react-native-safe-area-context": "*",
+ "react-native-screens": "*",
+ "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4"
+ },
+ "peerDependenciesMeta": {
+ "@react-navigation/drawer": {
+ "optional": true
+ },
+ "@testing-library/jest-native": {
+ "optional": true
+ },
+ "react-native-reanimated": {
+ "optional": true
+ },
+ "react-server-dom-webpack": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/expo-router/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/expo-splash-screen": {
+ "version": "0.30.10",
+ "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-0.30.10.tgz",
+ "integrity": "sha512-Tt9va/sLENQDQYeOQ6cdLdGvTZ644KR3YG9aRlnpcs2/beYjOX1LHT510EGzVN9ljUTg+1ebEo5GGt2arYtPjw==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/prebuild-config": "^9.0.10"
+ },
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
+ "node_modules/expo-status-bar": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-2.2.3.tgz",
+ "integrity": "sha512-+c8R3AESBoduunxTJ8353SqKAKpxL6DvcD8VKBuh81zzJyUUbfB4CVjr1GufSJEKsMzNPXZU+HJwXx7Xh7lx8Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-native-edge-to-edge": "1.6.0",
+ "react-native-is-edge-to-edge": "^1.1.6"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/exponential-backoff": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz",
+ "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "license": "MIT"
+ },
+ "node_modules/fastq": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fb-watchman": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+ "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bser": "2.1.1"
+ }
+ },
+ "node_modules/fbjs": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz",
+ "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==",
+ "license": "MIT",
+ "dependencies": {
+ "cross-fetch": "^3.1.5",
+ "fbjs-css-vars": "^1.0.0",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^1.0.35"
+ }
+ },
+ "node_modules/fbjs-css-vars": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
+ "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==",
+ "license": "MIT"
+ },
+ "node_modules/fbjs/node_modules/promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "license": "MIT",
+ "dependencies": {
+ "asap": "~2.0.3"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/filter-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
+ "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flow-enums-runtime": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz",
+ "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==",
+ "license": "MIT"
+ },
+ "node_modules/fontfaceobserver": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz",
+ "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/for-each": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/freeport-async": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/freeport-async/-/freeport-async-2.0.0.tgz",
+ "integrity": "sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "license": "ISC"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/generator-function": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+ "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-package-type": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/getenv": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz",
+ "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/glob": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hermes-estree": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
+ "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
+ "license": "MIT"
+ },
+ "node_modules/hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.25.1"
+ }
+ },
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hoist-non-react-statics/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ },
+ "node_modules/hosted-git-info": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
+ "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^10.0.1"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/hosted-git-info/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
+ },
+ "node_modules/html-parse-stringify": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.1.0.tgz",
+ "integrity": "sha512-E0oAXcELOtsXe+BmpJ2EZyedbldPpriV5vICzEuo6xjC/D1lDukOI7KrpfQGF2Qc4wWEy0nk3bFORS2K5ZAhFQ==",
+ "license": "MIT",
+ "dependencies": {
+ "void-elements": "3.1.0"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/http-errors/node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/hyphenate-style-name": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
+ "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/i18next": {
+ "version": "25.10.10",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.10.10.tgz",
+ "integrity": "sha512-cqUW2Z3EkRx7NqSyywjkgCLK7KLCL6IFVFcONG7nVYIJ3ekZ1/N5jUsihHV6Bq37NfhgtczxJcxduELtjTwkuQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://www.locize.com/i18next"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.locize.com"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.29.2"
+ },
+ "peerDependencies": {
+ "typescript": "^5 || ^6"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/image-size": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
+ "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
+ "license": "MIT",
+ "dependencies": {
+ "queue": "6.0.2"
+ },
+ "bin": {
+ "image-size": "bin/image-size.js"
+ },
+ "engines": {
+ "node": ">=16.x"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
+ "license": "MIT",
+ "dependencies": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/import-fresh/node_modules/resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "license": "ISC"
+ },
+ "node_modules/inline-style-prefixer": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz",
+ "integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==",
+ "license": "MIT",
+ "dependencies": {
+ "css-in-js-utils": "^3.1.0"
+ }
+ },
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "node_modules/is-arguments": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
+ "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "license": "MIT"
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.2",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
+ "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-generator-function": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
+ "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.4",
+ "generator-function": "^2.0.0",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-nan": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
+ "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "license": "MIT",
+ "dependencies": {
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "license": "ISC"
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
+ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-instrument": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+ "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/core": "^7.12.3",
+ "@babel/parser": "^7.14.7",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.2.0",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/jest-environment-node": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
+ "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-get-type": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
+ "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-haste-map": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
+ "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/graceful-fs": "^4.1.3",
+ "@types/node": "*",
+ "anymatch": "^3.0.3",
+ "fb-watchman": "^2.0.0",
+ "graceful-fs": "^4.2.9",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "walker": "^1.0.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "^2.3.2"
+ }
+ },
+ "node_modules/jest-message-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
+ "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.12.13",
+ "@jest/types": "^29.6.3",
+ "@types/stack-utils": "^2.0.0",
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "micromatch": "^4.0.4",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-mock": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
+ "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-regex-util": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
+ "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
+ "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "graceful-fs": "^4.2.9",
+ "picomatch": "^2.2.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-util/node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/jest-validate": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz",
+ "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "camelcase": "^6.2.0",
+ "chalk": "^4.0.0",
+ "jest-get-type": "^29.6.3",
+ "leven": "^3.1.0",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-validate/node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/jest-worker": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
+ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "jest-util": "^29.7.0",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-worker/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/jimp-compact": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/jimp-compact/-/jimp-compact-0.16.1.tgz",
+ "integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==",
+ "license": "MIT"
+ },
+ "node_modules/jiti": {
+ "version": "1.21.7",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
+ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
+ "license": "MIT",
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
+ "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodeca"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsc-safe-url": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz",
+ "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==",
+ "license": "0BSD"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lan-network": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.1.7.tgz",
+ "integrity": "sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ==",
+ "license": "MIT",
+ "bin": {
+ "lan-network": "dist/lan-network-cli.js"
+ }
+ },
+ "node_modules/leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lighthouse-logger": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz",
+ "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "debug": "^2.6.9",
+ "marky": "^1.2.2"
+ }
+ },
+ "node_modules/lighthouse-logger/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/lighthouse-logger/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/lightningcss": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.27.0.tgz",
+ "integrity": "sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.27.0",
+ "lightningcss-darwin-x64": "1.27.0",
+ "lightningcss-freebsd-x64": "1.27.0",
+ "lightningcss-linux-arm-gnueabihf": "1.27.0",
+ "lightningcss-linux-arm64-gnu": "1.27.0",
+ "lightningcss-linux-arm64-musl": "1.27.0",
+ "lightningcss-linux-x64-gnu": "1.27.0",
+ "lightningcss-linux-x64-musl": "1.27.0",
+ "lightningcss-win32-arm64-msvc": "1.27.0",
+ "lightningcss-win32-x64-msvc": "1.27.0"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz",
+ "integrity": "sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz",
+ "integrity": "sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz",
+ "integrity": "sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz",
+ "integrity": "sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz",
+ "integrity": "sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz",
+ "integrity": "sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz",
+ "integrity": "sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz",
+ "integrity": "sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz",
+ "integrity": "sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.27.0.tgz",
+ "integrity": "sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.throttle": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
+ "license": "MIT"
+ },
+ "node_modules/log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-symbols/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-symbols/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
+ "node_modules/log-symbols/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/log-symbols/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-symbols/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/lucide-react-native": {
+ "version": "0.511.0",
+ "resolved": "https://registry.npmjs.org/lucide-react-native/-/lucide-react-native-0.511.0.tgz",
+ "integrity": "sha512-brCrakogilGx3inT0em8HUU11dsxyu62+P6sjqU7WKgkfcIc8Q0Ya3zDcBQ8EG3c1HsCSvgFT5tWLetVFAsqhQ==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-native": "*",
+ "react-native-svg": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0"
+ }
+ },
+ "node_modules/makeerror": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
+ "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tmpl": "1.0.5"
+ }
+ },
+ "node_modules/marky": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz",
+ "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.0.14",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
+ "license": "CC0-1.0"
+ },
+ "node_modules/memoize-one": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
+ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
+ "license": "MIT"
+ },
+ "node_modules/merge-options": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
+ "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-plain-obj": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "license": "MIT"
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/metro": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.82.5.tgz",
+ "integrity": "sha512-8oAXxL7do8QckID/WZEKaIFuQJFUTLzfVcC48ghkHhNK2RGuQq8Xvf4AVd+TUA0SZtX0q8TGNXZ/eba1ckeGCg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.24.7",
+ "@babel/core": "^7.25.2",
+ "@babel/generator": "^7.25.0",
+ "@babel/parser": "^7.25.3",
+ "@babel/template": "^7.25.0",
+ "@babel/traverse": "^7.25.3",
+ "@babel/types": "^7.25.2",
+ "accepts": "^1.3.7",
+ "chalk": "^4.0.0",
+ "ci-info": "^2.0.0",
+ "connect": "^3.6.5",
+ "debug": "^4.4.0",
+ "error-stack-parser": "^2.0.6",
+ "flow-enums-runtime": "^0.0.6",
+ "graceful-fs": "^4.2.4",
+ "hermes-parser": "0.29.1",
+ "image-size": "^1.0.2",
+ "invariant": "^2.2.4",
+ "jest-worker": "^29.7.0",
+ "jsc-safe-url": "^0.2.2",
+ "lodash.throttle": "^4.1.1",
+ "metro-babel-transformer": "0.82.5",
+ "metro-cache": "0.82.5",
+ "metro-cache-key": "0.82.5",
+ "metro-config": "0.82.5",
+ "metro-core": "0.82.5",
+ "metro-file-map": "0.82.5",
+ "metro-resolver": "0.82.5",
+ "metro-runtime": "0.82.5",
+ "metro-source-map": "0.82.5",
+ "metro-symbolicate": "0.82.5",
+ "metro-transform-plugins": "0.82.5",
+ "metro-transform-worker": "0.82.5",
+ "mime-types": "^2.1.27",
+ "nullthrows": "^1.1.1",
+ "serialize-error": "^2.1.0",
+ "source-map": "^0.5.6",
+ "throat": "^5.0.0",
+ "ws": "^7.5.10",
+ "yargs": "^17.6.2"
+ },
+ "bin": {
+ "metro": "src/cli.js"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-babel-transformer": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.82.5.tgz",
+ "integrity": "sha512-W/scFDnwJXSccJYnOFdGiYr9srhbHPdxX9TvvACOFsIXdLilh3XuxQl/wXW6jEJfgIb0jTvoTlwwrqvuwymr6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.25.2",
+ "flow-enums-runtime": "^0.0.6",
+ "hermes-parser": "0.29.1",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-babel-transformer/node_modules/hermes-estree": {
+ "version": "0.29.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz",
+ "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==",
+ "license": "MIT"
+ },
+ "node_modules/metro-babel-transformer/node_modules/hermes-parser": {
+ "version": "0.29.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz",
+ "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==",
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.29.1"
+ }
+ },
+ "node_modules/metro-cache": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.82.5.tgz",
+ "integrity": "sha512-AwHV9607xZpedu1NQcjUkua8v7HfOTKfftl6Vc9OGr/jbpiJX6Gpy8E/V9jo/U9UuVYX2PqSUcVNZmu+LTm71Q==",
+ "license": "MIT",
+ "dependencies": {
+ "exponential-backoff": "^3.1.1",
+ "flow-enums-runtime": "^0.0.6",
+ "https-proxy-agent": "^7.0.5",
+ "metro-core": "0.82.5"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-cache-key": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.82.5.tgz",
+ "integrity": "sha512-qpVmPbDJuRLrT4kcGlUouyqLGssJnbTllVtvIgXfR7ZuzMKf0mGS+8WzcqzNK8+kCyakombQWR0uDd8qhWGJcA==",
+ "license": "MIT",
+ "dependencies": {
+ "flow-enums-runtime": "^0.0.6"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-config": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.82.5.tgz",
+ "integrity": "sha512-/r83VqE55l0WsBf8IhNmc/3z71y2zIPe5kRSuqA5tY/SL/ULzlHUJEMd1szztd0G45JozLwjvrhAzhDPJ/Qo/g==",
+ "license": "MIT",
+ "dependencies": {
+ "connect": "^3.6.5",
+ "cosmiconfig": "^5.0.5",
+ "flow-enums-runtime": "^0.0.6",
+ "jest-validate": "^29.7.0",
+ "metro": "0.82.5",
+ "metro-cache": "0.82.5",
+ "metro-core": "0.82.5",
+ "metro-runtime": "0.82.5"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-core": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.82.5.tgz",
+ "integrity": "sha512-OJL18VbSw2RgtBm1f2P3J5kb892LCVJqMvslXxuxjAPex8OH7Eb8RBfgEo7VZSjgb/LOf4jhC4UFk5l5tAOHHA==",
+ "license": "MIT",
+ "dependencies": {
+ "flow-enums-runtime": "^0.0.6",
+ "lodash.throttle": "^4.1.1",
+ "metro-resolver": "0.82.5"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-file-map": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.82.5.tgz",
+ "integrity": "sha512-vpMDxkGIB+MTN8Af5hvSAanc6zXQipsAUO+XUx3PCQieKUfLwdoa8qaZ1WAQYRpaU+CJ8vhBcxtzzo3d9IsCIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "fb-watchman": "^2.0.0",
+ "flow-enums-runtime": "^0.0.6",
+ "graceful-fs": "^4.2.4",
+ "invariant": "^2.2.4",
+ "jest-worker": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "nullthrows": "^1.1.1",
+ "walker": "^1.0.7"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-minify-terser": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.82.5.tgz",
+ "integrity": "sha512-v6Nx7A4We6PqPu/ta1oGTqJ4Usz0P7c+3XNeBxW9kp8zayS3lHUKR0sY0wsCHInxZlNAEICx791x+uXytFUuwg==",
+ "license": "MIT",
+ "dependencies": {
+ "flow-enums-runtime": "^0.0.6",
+ "terser": "^5.15.0"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-resolver": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.82.5.tgz",
+ "integrity": "sha512-kFowLnWACt3bEsuVsaRNgwplT8U7kETnaFHaZePlARz4Fg8tZtmRDUmjaD68CGAwc0rwdwNCkWizLYpnyVcs2g==",
+ "license": "MIT",
+ "dependencies": {
+ "flow-enums-runtime": "^0.0.6"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-runtime": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.82.5.tgz",
+ "integrity": "sha512-rQZDoCUf7k4Broyw3Ixxlq5ieIPiR1ULONdpcYpbJQ6yQ5GGEyYjtkztGD+OhHlw81LCR2SUAoPvtTus2WDK5g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.25.0",
+ "flow-enums-runtime": "^0.0.6"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-source-map": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.82.5.tgz",
+ "integrity": "sha512-wH+awTOQJVkbhn2SKyaw+0cd+RVSCZ3sHVgyqJFQXIee/yLs3dZqKjjeKKhhVeudgjXo7aE/vSu/zVfcQEcUfw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.25.3",
+ "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3",
+ "@babel/types": "^7.25.2",
+ "flow-enums-runtime": "^0.0.6",
+ "invariant": "^2.2.4",
+ "metro-symbolicate": "0.82.5",
+ "nullthrows": "^1.1.1",
+ "ob1": "0.82.5",
+ "source-map": "^0.5.6",
+ "vlq": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-symbolicate": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.82.5.tgz",
+ "integrity": "sha512-1u+07gzrvYDJ/oNXuOG1EXSvXZka/0JSW1q2EYBWerVKMOhvv9JzDGyzmuV7hHbF2Hg3T3S2uiM36sLz1qKsiw==",
+ "license": "MIT",
+ "dependencies": {
+ "flow-enums-runtime": "^0.0.6",
+ "invariant": "^2.2.4",
+ "metro-source-map": "0.82.5",
+ "nullthrows": "^1.1.1",
+ "source-map": "^0.5.6",
+ "vlq": "^1.0.0"
+ },
+ "bin": {
+ "metro-symbolicate": "src/index.js"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-transform-plugins": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.82.5.tgz",
+ "integrity": "sha512-57Bqf3rgq9nPqLrT2d9kf/2WVieTFqsQ6qWHpEng5naIUtc/Iiw9+0bfLLWSAw0GH40iJ4yMjFcFJDtNSYynMA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.25.2",
+ "@babel/generator": "^7.25.0",
+ "@babel/template": "^7.25.0",
+ "@babel/traverse": "^7.25.3",
+ "flow-enums-runtime": "^0.0.6",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro-transform-worker": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.82.5.tgz",
+ "integrity": "sha512-mx0grhAX7xe+XUQH6qoHHlWedI8fhSpDGsfga7CpkO9Lk9W+aPitNtJWNGrW8PfjKEWbT9Uz9O50dkI8bJqigw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.25.2",
+ "@babel/generator": "^7.25.0",
+ "@babel/parser": "^7.25.3",
+ "@babel/types": "^7.25.2",
+ "flow-enums-runtime": "^0.0.6",
+ "metro": "0.82.5",
+ "metro-babel-transformer": "0.82.5",
+ "metro-cache": "0.82.5",
+ "metro-cache-key": "0.82.5",
+ "metro-minify-terser": "0.82.5",
+ "metro-source-map": "0.82.5",
+ "metro-transform-plugins": "0.82.5",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/metro/node_modules/ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "license": "MIT"
+ },
+ "node_modules/metro/node_modules/hermes-estree": {
+ "version": "0.29.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz",
+ "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==",
+ "license": "MIT"
+ },
+ "node_modules/metro/node_modules/hermes-parser": {
+ "version": "0.29.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz",
+ "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==",
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.29.1"
+ }
+ },
+ "node_modules/metro/node_modules/ws": {
+ "version": "7.5.13",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz",
+ "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/micromatch/node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types/node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "license": "MIT",
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.17",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz",
+ "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/nativewind": {
+ "version": "4.1.23",
+ "resolved": "https://registry.npmjs.org/nativewind/-/nativewind-4.1.23.tgz",
+ "integrity": "sha512-oLX3suGI6ojQqWxdQezOSM5GmJ4KvMnMtmaSMN9Ggb5j7ysFt4nHxb1xs8RDjZR7BWc+bsetNJU8IQdQMHqRpg==",
+ "license": "MIT",
+ "dependencies": {
+ "comment-json": "^4.2.5",
+ "debug": "^4.3.7",
+ "react-native-css-interop": "0.1.22"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "tailwindcss": ">3.3.0"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/nested-error-stacks": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.0.1.tgz",
+ "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==",
+ "license": "MIT"
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-forge": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
+ "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
+ "license": "(BSD-3-Clause OR GPL-2.0)",
+ "engines": {
+ "node": ">= 6.13.0"
+ }
+ },
+ "node_modules/node-int64": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.53",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz",
+ "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-package-arg": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz",
+ "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==",
+ "license": "ISC",
+ "dependencies": {
+ "hosted-git-info": "^7.0.0",
+ "proc-log": "^4.0.0",
+ "semver": "^7.3.5",
+ "validate-npm-package-name": "^5.0.0"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/npm-package-arg/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/nullthrows": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
+ "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==",
+ "license": "MIT"
+ },
+ "node_modules/ob1": {
+ "version": "0.82.5",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.82.5.tgz",
+ "integrity": "sha512-QyQQ6e66f+Ut/qUVjEce0E/wux5nAGLXYZDn1jr15JWstHsCH3l6VVrg8NKDptW9NEiBXKOJeGF/ydxeSDF3IQ==",
+ "license": "MIT",
+ "dependencies": {
+ "flow-enums-runtime": "^0.0.6"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/object-is": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
+ "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+ "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/on-headers": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
+ "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/open": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
+ "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^2.0.0",
+ "is-wsl": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz",
+ "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^2.4.2",
+ "cli-cursor": "^2.1.0",
+ "cli-spinners": "^2.0.0",
+ "log-symbols": "^2.2.0",
+ "strip-ansi": "^5.2.0",
+ "wcwidth": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ora/node_modules/ansi-regex": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
+ "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ora/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ora/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ora/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/ora/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
+ "node_modules/ora/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/ora/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ora/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ora/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "license": "MIT",
+ "dependencies": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/parse-png": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/parse-png/-/parse-png-2.1.0.tgz",
+ "integrity": "sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==",
+ "license": "MIT",
+ "dependencies": {
+ "pngjs": "^3.3.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "license": "MIT"
+ },
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.2.tgz",
+ "integrity": "sha512-cfDHL6LStTEKlNilboNtobT/kEa30PtAf2Q1OgszfrG/rpVl1xaFWT9ktfkS306GmHgmnad1Sw4wabhlvFtsTw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
+ "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/plist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz",
+ "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==",
+ "license": "MIT",
+ "dependencies": {
+ "@xmldom/xmldom": "^0.9.10",
+ "base64-js": "^1.5.1",
+ "xmlbuilder": "^15.1.1"
+ },
+ "engines": {
+ "node": ">=10.4.0"
+ }
+ },
+ "node_modules/plist/node_modules/@xmldom/xmldom": {
+ "version": "0.9.10",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.10.tgz",
+ "integrity": "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.6"
+ }
+ },
+ "node_modules/pngjs": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
+ "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.49",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
+ "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
+ "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
+ "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "lilconfig": "^3.1.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "jiti": ">=1.21.0",
+ "postcss": ">=8.0.9",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+ "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "postcss-selector-parser": "^6.1.1"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz",
+ "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "license": "MIT"
+ },
+ "node_modules/pretty-bytes": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
+ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/pretty-format/node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "license": "MIT"
+ },
+ "node_modules/proc-log": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz",
+ "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==",
+ "license": "ISC",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/promise": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
+ "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
+ "license": "MIT",
+ "dependencies": {
+ "asap": "~2.0.6"
+ }
+ },
+ "node_modules/prompts": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qrcode-terminal": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz",
+ "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==",
+ "bin": {
+ "qrcode-terminal": "bin/qrcode-terminal.js"
+ }
+ },
+ "node_modules/query-string": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
+ "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==",
+ "license": "MIT",
+ "dependencies": {
+ "decode-uri-component": "^0.2.2",
+ "filter-obj": "^1.1.0",
+ "split-on-first": "^1.0.0",
+ "strict-uri-encode": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/queue": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
+ "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "~2.0.3"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.0.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
+ "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-devtools-core": {
+ "version": "6.1.5",
+ "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz",
+ "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==",
+ "license": "MIT",
+ "dependencies": {
+ "shell-quote": "^1.6.1",
+ "ws": "^7"
+ }
+ },
+ "node_modules/react-devtools-core/node_modules/ws": {
+ "version": "7.5.13",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz",
+ "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.0.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
+ "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.25.0"
+ },
+ "peerDependencies": {
+ "react": "^19.0.0"
+ }
+ },
+ "node_modules/react-fast-compare": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
+ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
+ "license": "MIT"
+ },
+ "node_modules/react-freeze": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz",
+ "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "react": ">=17.0.0"
+ }
+ },
+ "node_modules/react-i18next": {
+ "version": "16.6.6",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.6.6.tgz",
+ "integrity": "sha512-ZgL2HUoW34UKUkOV7uSQFE1CDnRPD+tCR3ywSuWH7u2iapnz86U8Bi3Vrs620qNDzCf1F47NxglCEkchCTDOHw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.29.2",
+ "html-parse-stringify": "^3.0.1",
+ "use-sync-external-store": "^1.6.0"
+ },
+ "peerDependencies": {
+ "i18next": ">= 25.10.9",
+ "react": ">= 16.8.0",
+ "typescript": "^5 || ^6"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-is": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz",
+ "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==",
+ "license": "MIT"
+ },
+ "node_modules/react-native": {
+ "version": "0.79.6",
+ "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.79.6.tgz",
+ "integrity": "sha512-kvIWSmf4QPfY41HC25TR285N7Fv0Pyn3DAEK8qRL9dA35usSaxsJkHfw+VqnonqJjXOaoKCEanwudRAJ60TBGA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jest/create-cache-key-function": "^29.7.0",
+ "@react-native/assets-registry": "0.79.6",
+ "@react-native/codegen": "0.79.6",
+ "@react-native/community-cli-plugin": "0.79.6",
+ "@react-native/gradle-plugin": "0.79.6",
+ "@react-native/js-polyfills": "0.79.6",
+ "@react-native/normalize-colors": "0.79.6",
+ "@react-native/virtualized-lists": "0.79.6",
+ "abort-controller": "^3.0.0",
+ "anser": "^1.4.9",
+ "ansi-regex": "^5.0.0",
+ "babel-jest": "^29.7.0",
+ "babel-plugin-syntax-hermes-parser": "0.25.1",
+ "base64-js": "^1.5.1",
+ "chalk": "^4.0.0",
+ "commander": "^12.0.0",
+ "event-target-shim": "^5.0.1",
+ "flow-enums-runtime": "^0.0.6",
+ "glob": "^7.1.1",
+ "invariant": "^2.2.4",
+ "jest-environment-node": "^29.7.0",
+ "memoize-one": "^5.0.0",
+ "metro-runtime": "^0.82.0",
+ "metro-source-map": "^0.82.0",
+ "nullthrows": "^1.1.1",
+ "pretty-format": "^29.7.0",
+ "promise": "^8.3.0",
+ "react-devtools-core": "^6.1.1",
+ "react-refresh": "^0.14.0",
+ "regenerator-runtime": "^0.13.2",
+ "scheduler": "0.25.0",
+ "semver": "^7.1.3",
+ "stacktrace-parser": "^0.1.10",
+ "whatwg-fetch": "^3.0.0",
+ "ws": "^6.2.3",
+ "yargs": "^17.6.2"
+ },
+ "bin": {
+ "react-native": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/react": "^19.0.0",
+ "react": "^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-native-css-interop": {
+ "version": "0.1.22",
+ "resolved": "https://registry.npmjs.org/react-native-css-interop/-/react-native-css-interop-0.1.22.tgz",
+ "integrity": "sha512-Mu01e+H9G+fxSWvwtgWlF5MJBJC4VszTCBXopIpeR171lbeBInHb8aHqoqRPxmJpi3xIHryzqKFOJYAdk7PBxg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/traverse": "^7.23.0",
+ "@babel/types": "^7.23.0",
+ "debug": "^4.3.7",
+ "lightningcss": "^1.27.0",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-native": "*",
+ "react-native-reanimated": ">=3.6.2",
+ "tailwindcss": "~3"
+ },
+ "peerDependenciesMeta": {
+ "react-native-safe-area-context": {
+ "optional": true
+ },
+ "react-native-svg": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/react-native-edge-to-edge": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/react-native-edge-to-edge/-/react-native-edge-to-edge-1.6.0.tgz",
+ "integrity": "sha512-2WCNdE3Qd6Fwg9+4BpbATUxCLcouF6YRY7K+J36KJ4l3y+tWN6XCqAC4DuoGblAAbb2sLkhEDp4FOlbOIot2Og==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-gesture-handler": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.24.0.tgz",
+ "integrity": "sha512-ZdWyOd1C8axKJHIfYxjJKCcxjWEpUtUWgTOVY2wynbiveSQDm8X/PDyAKXSer/GOtIpjudUbACOndZXCN3vHsw==",
+ "license": "MIT",
+ "dependencies": {
+ "@egjs/hammerjs": "^2.0.17",
+ "hoist-non-react-statics": "^3.3.0",
+ "invariant": "^2.2.4"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-is-edge-to-edge": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.3.1.tgz",
+ "integrity": "sha512-NIXU/iT5+ORyCc7p0z2nnlkouYKX425vuU1OEm6bMMtWWR9yvb+Xg5AZmImTKoF9abxCPqrKC3rOZsKzUYgYZA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-maps": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/react-native-maps/-/react-native-maps-1.20.1.tgz",
+ "integrity": "sha512-NZI3B5Z6kxAb8gzb2Wxzu/+P2SlFIg1waHGIpQmazDSCRkNoHNY4g96g+xS0QPSaG/9xRBbDNnd2f2/OW6t6LQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/geojson": "^7946.0.13"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": ">= 17.0.1",
+ "react-native": ">= 0.64.3",
+ "react-native-web": ">= 0.11"
+ },
+ "peerDependenciesMeta": {
+ "react-native-web": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-native-reanimated": {
+ "version": "3.17.5",
+ "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.17.5.tgz",
+ "integrity": "sha512-SxBK7wQfJ4UoWoJqQnmIC7ZjuNgVb9rcY5Xc67upXAFKftWg0rnkknTw6vgwnjRcvYThrjzUVti66XoZdDJGtw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-transform-arrow-functions": "^7.0.0-0",
+ "@babel/plugin-transform-class-properties": "^7.0.0-0",
+ "@babel/plugin-transform-classes": "^7.0.0-0",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0",
+ "@babel/plugin-transform-optional-chaining": "^7.0.0-0",
+ "@babel/plugin-transform-shorthand-properties": "^7.0.0-0",
+ "@babel/plugin-transform-template-literals": "^7.0.0-0",
+ "@babel/plugin-transform-unicode-regex": "^7.0.0-0",
+ "@babel/preset-typescript": "^7.16.7",
+ "convert-source-map": "^2.0.0",
+ "invariant": "^2.2.4",
+ "react-native-is-edge-to-edge": "1.1.7"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-reanimated/node_modules/react-native-is-edge-to-edge": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.1.7.tgz",
+ "integrity": "sha512-EH6i7E8epJGIcu7KpfXYXiV2JFIYITtq+rVS8uEb+92naMRBdxhTuS8Wn2Q7j9sqyO0B+Xbaaf9VdipIAmGW4w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-safe-area-context": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.4.0.tgz",
+ "integrity": "sha512-JaEThVyJcLhA+vU0NU8bZ0a1ih6GiF4faZ+ArZLqpYbL6j7R3caRqj+mE3lEtKCuHgwjLg3bCxLL1GPUJZVqUA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-screens": {
+ "version": "4.11.1",
+ "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.11.1.tgz",
+ "integrity": "sha512-F0zOzRVa3ptZfLpD0J8ROdo+y1fEPw+VBFq1MTY/iyDu08al7qFUO5hLMd+EYMda5VXGaTFCa8q7bOppUszhJw==",
+ "license": "MIT",
+ "dependencies": {
+ "react-freeze": "^1.0.0",
+ "react-native-is-edge-to-edge": "^1.1.7",
+ "warn-once": "^0.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-svg": {
+ "version": "15.11.2",
+ "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.11.2.tgz",
+ "integrity": "sha512-+YfF72IbWQUKzCIydlijV1fLuBsQNGMT6Da2kFlo1sh+LE3BIm/2Q7AR1zAAR6L0BFLi1WaQPLfFUC9bNZpOmw==",
+ "license": "MIT",
+ "dependencies": {
+ "css-select": "^5.1.0",
+ "css-tree": "^1.1.3",
+ "warn-once": "0.1.1"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-web": {
+ "version": "0.20.0",
+ "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.20.0.tgz",
+ "integrity": "sha512-OOSgrw+aON6R3hRosCau/xVxdLzbjEcsLysYedka0ZON4ZZe6n9xgeN9ZkoejhARM36oTlUgHIQqxGutEJ9Wxg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.6",
+ "@react-native/normalize-colors": "^0.74.1",
+ "fbjs": "^3.0.4",
+ "inline-style-prefixer": "^7.0.1",
+ "memoize-one": "^6.0.0",
+ "nullthrows": "^1.1.1",
+ "postcss-value-parser": "^4.2.0",
+ "styleq": "^0.1.3"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/react-native-web/node_modules/@react-native/normalize-colors": {
+ "version": "0.74.89",
+ "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.89.tgz",
+ "integrity": "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==",
+ "license": "MIT"
+ },
+ "node_modules/react-native-web/node_modules/memoize-one": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+ "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
+ "license": "MIT"
+ },
+ "node_modules/react-native/node_modules/brace-expansion": {
+ "version": "1.1.18",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
+ "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/react-native/node_modules/commander": {
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
+ "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-native/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/react-native/node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/react-native/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/react-native/node_modules/ws": {
+ "version": "6.2.6",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.6.tgz",
+ "integrity": "sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA==",
+ "license": "MIT",
+ "dependencies": {
+ "async-limiter": "~1.0.0"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
+ "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "license": "MIT",
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/readdirp/node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/regenerate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+ "license": "MIT"
+ },
+ "node_modules/regenerate-unicode-properties": {
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz",
+ "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==",
+ "license": "MIT",
+ "dependencies": {
+ "regenerate": "^1.4.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+ "license": "MIT"
+ },
+ "node_modules/regexpu-core": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz",
+ "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==",
+ "license": "MIT",
+ "dependencies": {
+ "regenerate": "^1.4.2",
+ "regenerate-unicode-properties": "^10.2.2",
+ "regjsgen": "^0.8.0",
+ "regjsparser": "^0.13.0",
+ "unicode-match-property-ecmascript": "^2.0.0",
+ "unicode-match-property-value-ecmascript": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regjsgen": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz",
+ "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==",
+ "license": "MIT"
+ },
+ "node_modules/regjsparser": {
+ "version": "0.13.2",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz",
+ "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "jsesc": "~3.1.0"
+ },
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/requireg": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/requireg/-/requireg-0.2.2.tgz",
+ "integrity": "sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==",
+ "dependencies": {
+ "nested-error-stacks": "~2.0.1",
+ "rc": "~1.2.7",
+ "resolve": "~1.7.1"
+ },
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/requireg/node_modules/resolve": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
+ "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
+ "license": "MIT",
+ "dependencies": {
+ "path-parse": "^1.0.5"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.12",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
+ "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-workspace-root": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-workspace-root/-/resolve-workspace-root-2.0.1.tgz",
+ "integrity": "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==",
+ "license": "MIT"
+ },
+ "node_modules/resolve.exports": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz",
+ "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/restore-cursor/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "license": "ISC"
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/brace-expansion": {
+ "version": "1.1.18",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
+ "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/rimraf/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/sax": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz",
+ "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=11.0.0"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
+ "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
+ "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "~0.5.2",
+ "http-errors": "~2.0.1",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "~2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "~2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/send/node_modules/debug/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/send/node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/serialize-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
+ "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "1.16.3",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
+ "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "~0.19.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/serve-static/node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/server-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz",
+ "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==",
+ "license": "MIT"
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "license": "MIT"
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/sf-symbols-typescript": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz",
+ "integrity": "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shallowequal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
+ "license": "MIT"
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shell-quote": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz",
+ "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/simple-plist": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz",
+ "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==",
+ "license": "MIT",
+ "dependencies": {
+ "bplist-creator": "0.1.0",
+ "bplist-parser": "0.3.1",
+ "plist": "^3.0.5"
+ }
+ },
+ "node_modules/simple-plist/node_modules/bplist-parser": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz",
+ "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==",
+ "license": "MIT",
+ "dependencies": {
+ "big-integer": "1.6.x"
+ },
+ "engines": {
+ "node": ">= 5.10.0"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+ "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
+ "license": "MIT"
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "license": "MIT"
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slugify": {
+ "version": "1.6.9",
+ "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.9.tgz",
+ "integrity": "sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/source-map-support/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/split-on-first": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
+ "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/stack-utils": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+ "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/stack-utils/node_modules/escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stackframe": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
+ "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
+ "license": "MIT"
+ },
+ "node_modules/stacktrace-parser": {
+ "version": "0.1.11",
+ "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz",
+ "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==",
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.7.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/standard-navigation": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/standard-navigation/-/standard-navigation-0.0.8.tgz",
+ "integrity": "sha512-TyVbo7INUDWtsUWDFn8RR7kwR87U0S4xHfLfbbnyeC581TmmyqQ+eM+nPw8rQTSD8QitRVcYfPaSHr/QJiUy1g==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/stream-buffers": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
+ "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==",
+ "license": "Unlicense",
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/strict-uri-encode": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
+ "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi/node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/structured-headers": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz",
+ "integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==",
+ "license": "MIT"
+ },
+ "node_modules/styleq": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.1.3.tgz",
+ "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==",
+ "license": "MIT"
+ },
+ "node_modules/sucrase": {
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+ "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "glob": "^10.3.10",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/sucrase/node_modules/commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-hyperlinks": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz",
+ "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0",
+ "supports-color": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "3.4.19",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
+ "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.6.0",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.3.2",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.21.7",
+ "lilconfig": "^3.1.3",
+ "micromatch": "^4.0.8",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.1.1",
+ "postcss": "^8.4.47",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0",
+ "postcss-nested": "^6.2.0",
+ "postcss-selector-parser": "^6.1.2",
+ "resolve": "^1.22.8",
+ "sucrase": "^3.35.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tar": {
+ "version": "7.5.22",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz",
+ "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tar/node_modules/yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/temp-dir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz",
+ "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/terminal-link": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
+ "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-escapes": "^4.2.1",
+ "supports-hyperlinks": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.49.2",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.2.tgz",
+ "integrity": "sha512-rGbJiKeQ4WDe3EXlDAIaQcwftVfv2Q8o1awFNfvXolJYKkb1AuZY1RTOmqx4LJXZENbWZA7eIsYGHuEzHsi1nQ==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.15.0",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "license": "MIT"
+ },
+ "node_modules/test-exclude": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+ "license": "ISC",
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/test-exclude/node_modules/brace-expansion": {
+ "version": "1.1.18",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
+ "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/test-exclude/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/test-exclude/node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "license": "MIT",
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "license": "MIT",
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/throat": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
+ "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
+ "license": "MIT"
+ },
+ "node_modules/tmpl": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT"
+ },
+ "node_modules/ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz",
+ "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==",
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/ua-parser-js": {
+ "version": "1.0.41",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz",
+ "integrity": "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ua-parser-js"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/faisalman"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/faisalman"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "ua-parser-js": "script/cli.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/undici": {
+ "version": "6.28.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
+ "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
+ "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
+ "license": "MIT"
+ },
+ "node_modules/unicode-canonical-property-names-ecmascript": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
+ "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-ecmascript": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
+ "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "unicode-canonical-property-names-ecmascript": "^2.0.0",
+ "unicode-property-aliases-ecmascript": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-value-ecmascript": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz",
+ "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-property-aliases-ecmascript": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz",
+ "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unique-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
+ "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+ "license": "MIT",
+ "dependencies": {
+ "crypto-random-string": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/use-latest-callback": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz",
+ "integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/util": {
+ "version": "0.12.5",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
+ "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "is-arguments": "^1.0.4",
+ "is-generator-function": "^1.0.7",
+ "is-typed-array": "^1.1.3",
+ "which-typed-array": "^1.1.2"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
+ "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
+ "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).",
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/validate-npm-package-name": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz",
+ "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==",
+ "license": "ISC",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vlq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz",
+ "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==",
+ "license": "MIT"
+ },
+ "node_modules/void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/walker": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "makeerror": "1.0.12"
+ }
+ },
+ "node_modules/warn-once": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz",
+ "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==",
+ "license": "MIT"
+ },
+ "node_modules/wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "license": "MIT",
+ "dependencies": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/whatwg-fetch": {
+ "version": "3.6.20",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
+ "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==",
+ "license": "MIT"
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/whatwg-url-without-unicode": {
+ "version": "8.0.0-3",
+ "resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz",
+ "integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^5.4.3",
+ "punycode": "^2.1.1",
+ "webidl-conversions": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/whatwg-url-without-unicode/node_modules/webidl-conversions": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+ "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.22",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz",
+ "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==",
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "for-each": "^0.3.5",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/wonka": {
+ "version": "6.3.6",
+ "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.6.tgz",
+ "integrity": "sha512-MXH+6mDHAZ2GuMpgKS055FR6v0xVP3XwquxIMYXgiW+FejHQlMGlvVRZT4qMCxR+bEo/FCtIdKxwej9WV3YQag==",
+ "license": "MIT"
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/wrap-ansi/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "node_modules/write-file-atomic": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
+ "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+ "license": "ISC",
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.7"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/write-file-atomic/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "license": "ISC"
+ },
+ "node_modules/ws": {
+ "version": "8.21.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz",
+ "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xcode": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz",
+ "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "simple-plist": "^1.1.0",
+ "uuid": "^7.0.3"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/xml2js": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz",
+ "integrity": "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==",
+ "license": "MIT",
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/xml2js/node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "15.1.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
+ "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "license": "ISC"
+ },
+ "node_modules/yargs": {
+ "version": "17.7.3",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz",
+ "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/yargs/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zustand": {
+ "version": "5.0.14",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.14.tgz",
+ "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=18.0.0",
+ "immer": ">=9.0.6",
+ "react": ">=18.0.0",
+ "use-sync-external-store": ">=1.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "use-sync-external-store": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..fc92962
--- /dev/null
+++ b/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "gishen-mob",
+ "version": "1.0.0",
+ "main": "expo-router/entry",
+ "scripts": {
+ "start": "expo start",
+ "android": "expo start --android",
+ "ios": "expo start --ios",
+ "web": "expo start --web",
+ "lint": "expo lint"
+ },
+ "dependencies": {
+ "@expo-google-fonts/plus-jakarta-sans": "^0.4.2",
+ "@expo/vector-icons": "^14.1.0",
+ "@react-native-async-storage/async-storage": "2.1.2",
+ "expo": "~53.0.0",
+ "expo-camera": "~16.1.11",
+ "expo-constants": "~17.1.7",
+ "expo-font": "~13.3.1",
+ "expo-image-picker": "~16.1.4",
+ "expo-linking": "~7.1.7",
+ "expo-local-authentication": "~16.0.5",
+ "expo-location": "~18.1.6",
+ "expo-notifications": "~0.31.4",
+ "expo-router": "~5.1.6",
+ "expo-splash-screen": "~0.30.10",
+ "expo-status-bar": "~2.2.3",
+ "i18next": "^25.7.2",
+ "lucide-react-native": "^0.511.0",
+ "nativewind": "4.1.23",
+ "react": "19.0.0",
+ "react-dom": "19.0.0",
+ "react-i18next": "^16.5.0",
+ "react-native": "0.79.6",
+ "react-native-gesture-handler": "~2.24.0",
+ "react-native-maps": "1.20.1",
+ "react-native-reanimated": "~3.17.4",
+ "react-native-safe-area-context": "5.4.0",
+ "react-native-screens": "~4.11.1",
+ "react-native-svg": "15.11.2",
+ "react-native-web": "^0.20.0",
+ "tailwindcss": "^3.4.17",
+ "zustand": "^5.0.3"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.26.0",
+ "@types/react": "~19.0.10",
+ "typescript": "~5.8.3"
+ },
+ "private": true
+}
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..13d6f79
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,40 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"],
+ presets: [require("nativewind/preset")],
+ theme: {
+ extend: {
+ colors: {
+ brand: "#A8C73A",
+ "brand-deep": "#93B22E",
+ "brand-text": "#748E22",
+ "brand-soft": "#ECF4D8",
+ "brand-wash": "#F6FAEC",
+ ink: "#101410",
+ "ink-secondary": "#5B6157",
+ muted: "#5B6157",
+ subtle: "#8A9188",
+ page: "#F7F8F5",
+ surface: "#FFFFFF",
+ "surface-alt": "#F1F3EC",
+ line: "#E9ECE2",
+ danger: "#D64545",
+ warn: "#E0870F",
+ accent: "#E0870F",
+ info: "#2F6FED",
+ },
+ borderRadius: {
+ card: "20px",
+ pill: "999px",
+ },
+ fontFamily: {
+ sans: ["Jakarta_400Regular"],
+ medium: ["Jakarta_500Medium"],
+ semibold: ["Jakarta_600SemiBold"],
+ bold: ["Jakarta_700Bold"],
+ extrabold: ["Jakarta_800ExtraBold"],
+ },
+ },
+ },
+ plugins: [],
+};
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..51caefb
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "expo/tsconfig.base",
+ "compilerOptions": {
+ "strict": true,
+ "resolveJsonModule": true,
+ "paths": {
+ "@/*": ["./*"]
+ }
+ },
+ "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts", "nativewind-env.d.ts"]
+}