diff --git a/docs/mobile/010-mobile-reader.md b/docs/mobile/010-mobile-reader.md
new file mode 100644
index 0000000..0e8c069
--- /dev/null
+++ b/docs/mobile/010-mobile-reader.md
@@ -0,0 +1,150 @@
+# 010 — Mobile EPUB Reader
+
+**Status:** Implemented
+**Created:** 2026-06-04
+
+## Objective
+
+Mirror the web reading experience (`frontend/src/pages/ReadingPage.tsx` and
+`frontend/src/components/reader/*`) inside the Expo app so users can open their
+uploaded library, read EPUBs with persisted progress and typography settings,
+and manage bookmarks/highlights — reusing the same Django REST API as the web
+client.
+
+The web EPUB renderer (`react-reader` / epub.js) is DOM-only, so mobile renders
+EPUBs with `@epubjs-react-native/core`, which runs epub.js inside a
+`react-native-webview`. This keeps behavior (CFI locations, themes, font
+controls, TOC, annotations) close to web while staying inside the managed Expo
+workflow.
+
+## Scope
+
+### Mirrored from web
+
+- EPUB rendering with swipe pagination (`flow: "paginated"`).
+- Resume position and debounced progress save (CFI + percentage).
+- Table of contents drawer with jump-to-chapter.
+- Reading settings: theme presets (light/sepia/paper/dark), font family, font
+ size, line spacing — persisted to `/api/reader/settings/`.
+- Bookmarks: bookmark the current page, list/jump/delete, and create highlights
+ from a text selection. Highlights are re-applied on open (best-effort).
+
+### Deferred (not in this pass)
+
+- PDF reading. PDF books show a placeholder pointing to the web reader.
+- Brightness and orientation-lock controls.
+- Per-highlight color picker (highlights use a single default color).
+- App-wide internationalization (web uses `react-i18n-lite`).
+
+## Architecture
+
+```
+LibraryScreen (EBook list)
+ | navigate("BookDetail", { ebookId })
+ v
+BookDetailScreen ----------------> ReaderScreen ({ ebookId })
+ |
+ GET /api/books/ebooks/:id/ (format guard)
+ |
+ epub? --------------------- pdf? -> placeholder
+ |
+ EpubReaderView (ReaderProvider)
+ |
+ expo-file-system downloadAsync(file/, Bearer token) -> file:// uri
+ |
+
+ |
+ onLocationChange -> debounce 800ms -> PATCH progress/
+ onSelected -> POST bookmarks/ (+ highlight annotation)
+ useReader().toc -> goToLocation(href)
+ settings change -> changeTheme / changeFontSize / changeFontFamily
+ + PATCH /api/reader/settings/ (debounced)
+```
+
+The ebook file is downloaded to the app cache with an `Authorization` header
+(the `/file/` endpoint is JWT-protected) and the local `file://` URI is handed
+to the renderer — mirroring how the web client downloads a blob rather than
+using a public/signed URL.
+
+## Mobile changes
+
+| File | Role |
+|------|------|
+| `mobile/src/api/client.ts` | Adds `apiClient`, `saveTokens`, `loadTokens`, `getApiBaseUrl` |
+| `mobile/src/api/ebooks.ts` | `/api/books/ebooks/` list/detail/toc + `getFileUrl(id)` |
+| `mobile/src/api/reader.ts` | Reader settings + per-book progress (mirrors web `api/reader.ts`) |
+| `mobile/src/api/annotations.ts` | Bookmarks CRUD against `/api/annotations/bookmarks/` |
+| `mobile/src/types/reader.ts` | `ReadingSettings`, `ReadingProgress` (full reader shapes) |
+| `mobile/src/types/index.ts` | `AppStackParamList`, `Bookmark`, `CreateMarkerPayload` |
+| `mobile/src/hooks/useReadingSettings.ts` | Loads + debounced-saves reader settings |
+| `mobile/src/utils/epubTheme.ts` | Font stacks, theme palettes, `buildEpubTheme()` |
+| `mobile/src/navigation/AppStack.tsx` | Native stack: Tabs / BookDetail / Reader |
+| `mobile/src/screens/LibraryScreen.tsx` | Lists user EBooks (`ebooksApi.list`) |
+| `mobile/src/screens/BookDetailScreen.tsx` | Metadata + start/resume button |
+| `mobile/src/screens/ReaderScreen.tsx` | Format guard: EPUB view vs PDF placeholder |
+| `mobile/src/components/reader/EpubReaderView.tsx` | Reader, progress, bookmarks, settings wiring |
+| `mobile/src/components/reader/ReaderToolbar.tsx` | Title, chapter, progress bar, action buttons |
+| `mobile/src/components/reader/TocModal.tsx` | Table of contents sheet |
+| `mobile/src/components/reader/ReadingSettingsModal.tsx` | Theme/font/size/spacing controls |
+| `mobile/src/components/reader/BookmarksModal.tsx` | Bookmarks & highlights list |
+| `mobile/App.tsx` | Wraps the tree in `GestureHandlerRootView` |
+
+Removed unused scaffolding: `mobile/src/navigation/AppNavigator.tsx`,
+`mobile/src/navigation/MainTabs.tsx`.
+
+## API contracts (consumed)
+
+| Method | Path | Purpose |
+|--------|------|---------|
+| GET | `/api/books/ebooks/` | User library list |
+| GET | `/api/books/ebooks/:id/` | EBook detail (format, progress, cover) |
+| GET | `/api/books/ebooks/:id/file/` | Stream EPUB bytes (JWT, owner) |
+| GET/PATCH | `/api/books/ebooks/:id/progress/` | Reading progress (`current_position`, `last_page`, `epub_location`) |
+| GET/PATCH | `/api/reader/settings/` | Reader typography/theme settings |
+| GET/POST/DELETE | `/api/annotations/bookmarks/` | Bookmarks & highlights (`ebook`, `epub_cfi`, `chapter_index`, ...) |
+
+## Settings mapping (web -> mobile)
+
+| Reader setting | Web (epub.js) | Mobile (`@epubjs-react-native/core`) |
+|----------------|---------------|--------------------------------------|
+| `theme` / colors | `themes.register/select` | `changeTheme(buildEpubTheme())` + `defaultTheme` |
+| `font_size` | `themes.fontSize` | `changeFontSize("Npx")` |
+| `font_family` | body font-family | `changeFontFamily(stack)` |
+| `line_height` | body line-height | `buildEpubTheme()` CSS rule |
+| `margin_width` | gap-based padding | not applied (deferred) |
+| `brightness` / `orientation_lock` | applied on web | deferred |
+
+## Dependencies added
+
+- `@epubjs-react-native/core@1.4.7`
+- `@epubjs-react-native/expo-file-system@1.1.4`
+- `react-native-webview@13.12.5`
+
+(`react-native-gesture-handler`, `react-native-reanimated`, and
+`expo-file-system` were already present.)
+
+## Configuration
+
+| Env var | Purpose |
+|---------|---------|
+| `EXPO_PUBLIC_API_URL` | Backend base URL (e.g. `http://10.0.2.2:8000` on Android emulator, LAN IP on a device) |
+
+## Compatibility notes
+
+- The Expo file-system adapter (`@epubjs-react-native/expo-file-system`) depends
+ only on `expo-file-system`, so the reader runs in Expo Go. (The library's
+ bare adapter pulls native `@dr.pogodin/react-native-fs`; that path is not
+ used here.)
+- React 19 / Expo SDK 52 may surface peer-dependency warnings for the
+ `@epubjs-react-native/*` packages.
+
+## Verification
+
+- [ ] Log in; Library lists the user's uploaded EBooks with covers/progress.
+- [ ] Open an EPUB; it renders and paginates by swipe.
+- [ ] Reopen a book; it resumes at the last position.
+- [ ] Change theme/font/size/spacing; the page updates and persists across reopen.
+- [ ] Open the TOC and jump to a chapter.
+- [ ] Bookmark the current page; it appears in the bookmarks list and can be re-opened/deleted.
+- [ ] Select text to create a highlight; it persists and re-renders on reopen.
+- [ ] Open a PDF book; the placeholder is shown instead of a crash.
diff --git a/mobile/.env.example b/mobile/.env.example
new file mode 100644
index 0000000..bfc9c40
--- /dev/null
+++ b/mobile/.env.example
@@ -0,0 +1,10 @@
+# Mobile (Expo) environment (example – never commit real secrets)
+# Base URL of the Django backend. Must be reachable from the device/emulator.
+# - Android emulator: http://10.0.2.2:8000
+# - iOS simulator: http://localhost:8000
+# - Physical device: http://:8000
+EXPO_PUBLIC_API_URL=http://10.0.2.2:8000
+
+# EAS Build: set per profile in mobile/eas.json or via:
+# eas secret:create --name EXPO_PUBLIC_API_URL --value https://your-api.example.com
+# Run all eas commands from mobile/ (not repo root).
diff --git a/mobile/App.tsx b/mobile/App.tsx
index 9b3eeea..c3a79d6 100644
--- a/mobile/App.tsx
+++ b/mobile/App.tsx
@@ -1,4 +1,8 @@
import React from "react";
+// Peer dependencies for @epubjs-react-native/core and gesture-handler.
+import "react-native-webview";
+import "react-native-reanimated";
+import { GestureHandlerRootView } from "react-native-gesture-handler";
import { NavigationContainer } from "@react-navigation/native";
import { StatusBar } from "expo-status-bar";
import { AuthProvider } from "./src/context/AuthContext";
@@ -6,11 +10,13 @@ import { RootNavigator } from "./src/navigation/RootNavigator";
export default function App() {
return (
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
-}
\ No newline at end of file
+}
diff --git a/mobile/app.json b/mobile/app.json
index 7ccd6b0..ef88074 100644
--- a/mobile/app.json
+++ b/mobile/app.json
@@ -21,7 +21,6 @@
"package": "com.cloudreader.app"
},
"plugins": [
- "expo-document-picker",
"expo-file-system"
]
}
diff --git a/mobile/eas.json b/mobile/eas.json
new file mode 100644
index 0000000..5c23e85
--- /dev/null
+++ b/mobile/eas.json
@@ -0,0 +1,42 @@
+{
+ "cli": {
+ "version": ">= 13.0.0",
+ "appVersionSource": "remote"
+ },
+ "build": {
+ "base": {
+ "node": "20.18.0",
+ "env": {
+ "EXPO_PUBLIC_API_URL": "https://api.example.com"
+ }
+ },
+ "development": {
+ "extends": "base",
+ "developmentClient": true,
+ "distribution": "internal",
+ "ios": {
+ "simulator": true
+ },
+ "android": {
+ "buildType": "apk"
+ },
+ "env": {
+ "EXPO_PUBLIC_API_URL": "http://10.0.2.2:8000"
+ }
+ },
+ "preview": {
+ "extends": "base",
+ "distribution": "internal",
+ "android": {
+ "buildType": "apk"
+ }
+ },
+ "production": {
+ "extends": "base",
+ "autoIncrement": true
+ }
+ },
+ "submit": {
+ "production": {}
+ }
+}
diff --git a/mobile/metro.config.js b/mobile/metro.config.js
new file mode 100644
index 0000000..cd02e9a
--- /dev/null
+++ b/mobile/metro.config.js
@@ -0,0 +1,25 @@
+const { getDefaultConfig } = require("expo/metro-config");
+const path = require("path");
+
+const projectRoot = __dirname;
+const monorepoRoot = path.resolve(projectRoot, "..");
+
+/**
+ * Expo SDK 52+ configures Metro for Yarn/npm/pnpm workspaces automatically
+ * when using expo/metro-config. This file keeps an explicit monorepo root so
+ * @cloud-reader/shared (packages/shared) resolves reliably in dev and on EAS.
+ *
+ * If you previously added manual watchFolders/nodeModulesPaths and things
+ * work, prefer this minimal config. After changes: npx expo start --clear
+ *
+ * @see https://docs.expo.dev/guides/monorepos/
+ */
+const config = getDefaultConfig(projectRoot);
+
+config.watchFolders = [monorepoRoot];
+config.resolver.nodeModulesPaths = [
+ path.resolve(projectRoot, "node_modules"),
+ path.resolve(monorepoRoot, "node_modules"),
+];
+
+module.exports = config;
diff --git a/mobile/package.json b/mobile/package.json
index 231691c..f52bbba 100644
--- a/mobile/package.json
+++ b/mobile/package.json
@@ -8,7 +8,11 @@
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
- "lint": "eslint ."
+ "lint": "eslint .",
+ "eas:init": "eas init",
+ "eas:build:dev": "eas build --profile development --platform all",
+ "eas:build:preview": "eas build --profile preview --platform all",
+ "eas:build:prod": "eas build --profile production --platform all"
},
"dependencies": {
"expo": "~52.0.0",
@@ -22,10 +26,12 @@
"@react-navigation/bottom-tabs": "^7.0.0",
"axios": "^1.7.9",
"@react-native-async-storage/async-storage": "2.1.0",
- "expo-document-picker": "~13.0.0",
+ "@epubjs-react-native/core": "1.4.7",
+ "@epubjs-react-native/expo-file-system": "1.1.4",
"expo-file-system": "~18.0.0",
"react-native-gesture-handler": "~2.20.0",
"react-native-reanimated": "~3.16.0",
+ "react-native-webview": "13.12.5",
"@cloud-reader/shared": "*"
},
"devDependencies": {
diff --git a/mobile/src/api/annotations.ts b/mobile/src/api/annotations.ts
index 434fb89..ef2d259 100644
--- a/mobile/src/api/annotations.ts
+++ b/mobile/src/api/annotations.ts
@@ -1,55 +1,31 @@
import api from "./client";
-import type {
- Bookmark,
- Note,
- CreateBookmarkPayload,
- CreateNotePayload,
- PaginatedResponse,
-} from "@cloud-reader/shared";
+import type { PaginatedResponse } from "@cloud-reader/shared";
+import type { Bookmark, CreateMarkerPayload } from "../types";
-export function fetchBookmarks(
- bookId?: string,
+export async function fetchBookmarks(
+ ebookId?: string | number,
): Promise> {
- const params = bookId ? { book: bookId } : {};
- return api
- .get>("/api/annotations/bookmarks/", { params })
- .then((res) => res.data);
+ const params: Record = {};
+ if (ebookId != null && ebookId !== "") {
+ params.ebook = String(ebookId);
+ }
+ const { data } = await api.get>(
+ "/api/annotations/bookmarks/",
+ { params },
+ );
+ return data;
}
-export function createBookmark(
- payload: CreateBookmarkPayload,
+export async function createMarker(
+ payload: CreateMarkerPayload,
): Promise {
- return api
- .post("/api/annotations/bookmarks/", payload)
- .then((res) => res.data);
+ const { data } = await api.post(
+ "/api/annotations/bookmarks/",
+ payload,
+ );
+ return data;
}
-export function deleteBookmark(id: string): Promise {
- return api.delete(`/api/annotations/bookmarks/${id}/`).then(() => {});
+export async function deleteBookmark(id: string): Promise {
+ await api.delete(`/api/annotations/bookmarks/${id}/`);
}
-
-export function fetchNotes(bookId?: string): Promise> {
- const params = bookId ? { book: bookId } : {};
- return api
- .get>("/api/annotations/notes/", { params })
- .then((res) => res.data);
-}
-
-export function createNote(payload: CreateNotePayload): Promise {
- return api
- .post("/api/annotations/notes/", payload)
- .then((res) => res.data);
-}
-
-export function updateNote(
- id: string,
- content: string,
-): Promise {
- return api
- .patch(`/api/annotations/notes/${id}/`, { content })
- .then((res) => res.data);
-}
-
-export function deleteNote(id: string): Promise {
- return api.delete(`/api/annotations/notes/${id}/`).then(() => {});
-}
\ No newline at end of file
diff --git a/mobile/src/api/books.ts b/mobile/src/api/books.ts
index 9045b61..f273356 100644
--- a/mobile/src/api/books.ts
+++ b/mobile/src/api/books.ts
@@ -1,31 +1,12 @@
import api from "./client";
import type { Book, PaginatedResponse } from "@cloud-reader/shared";
-export function fetchBooks(
- page = 1,
- pageSize = 20,
-): Promise> {
- return api
- .get>("/api/books/", {
- params: { page, page_size: pageSize },
- })
- .then((res) => res.data);
-}
-
-export function fetchBook(id: string): Promise {
- return api.get(`/api/books/${id}/`).then((res) => res.data);
-}
-
export function searchBooks(
query: string,
): Promise> {
return api
- .get>("/api/books/search/", {
+ .get>("/api/books/", {
params: { q: query },
})
.then((res) => res.data);
}
-
-export function deleteBook(id: string): Promise {
- return api.delete(`/api/books/${id}/`).then(() => {});
-}
\ No newline at end of file
diff --git a/mobile/src/api/client.ts b/mobile/src/api/client.ts
index f1963dc..f6e832d 100644
--- a/mobile/src/api/client.ts
+++ b/mobile/src/api/client.ts
@@ -1,5 +1,6 @@
import axios, { type AxiosError, type InternalAxiosRequestConfig } from "axios";
import AsyncStorage from "@react-native-async-storage/async-storage";
+import type { TokenResponse } from "@cloud-reader/shared";
const STORAGE_KEYS = {
ACCESS_TOKEN: "access_token",
@@ -39,6 +40,26 @@ async function clearTokens(): Promise {
]);
}
+async function saveTokens(tokens: TokenResponse): Promise {
+ await setTokens(tokens.access, tokens.refresh);
+}
+
+async function loadTokens(): Promise {
+ const [access, refresh] = await Promise.all([
+ getAccessToken(),
+ getRefreshToken(),
+ ]);
+ if (!access || !refresh) {
+ return null;
+ }
+ return { access, refresh };
+}
+
+/** Absolute base URL used for direct (non-axios) requests like file downloads. */
+function getApiBaseUrl(): string {
+ return api.defaults.baseURL ?? "";
+}
+
// ── Request interceptor ─────────────────────────────────────────────
api.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {
@@ -136,5 +157,14 @@ api.interceptors.response.use(
},
);
-export { getAccessToken, getRefreshToken, setTokens, clearTokens };
+const apiClient = api;
+
+export {
+ apiClient,
+ getAccessToken,
+ saveTokens,
+ loadTokens,
+ clearTokens,
+ getApiBaseUrl,
+};
export default api;
\ No newline at end of file
diff --git a/mobile/src/api/ebooks.ts b/mobile/src/api/ebooks.ts
index 26b5d50..8e1e504 100644
--- a/mobile/src/api/ebooks.ts
+++ b/mobile/src/api/ebooks.ts
@@ -1,54 +1,35 @@
-import { apiClient } from "./client";
+import { apiClient, getApiBaseUrl } from "./client";
import type {
EBookListItem,
EBookDetail,
- ReadingProgress,
- ReadingSettings,
TocResponse,
- ContentResponse,
PaginatedResponse,
} from "@cloud-reader/shared";
export const ebooksApi = {
- /** List uploaded e-books */
+ /** List the authenticated user's uploaded e-books */
list() {
- return apiClient.get>("/api/ebooks/");
+ return apiClient.get>(
+ "/api/books/ebooks/",
+ );
},
- /** Get e-book detail */
+ /** Get e-book detail (metadata, format, progress) */
get(id: number) {
- return apiClient.get(`/api/ebooks/${id}/`);
+ return apiClient.get(`/api/books/ebooks/${id}/`);
},
- /** Get table of contents */
+ /** Get the table of contents (used as a fallback for chapter navigation) */
getToc(id: number) {
- return apiClient.get(`/api/ebooks/${id}/toc/`);
+ return apiClient.get(`/api/books/ebooks/${id}/toc/`);
},
- /** Get page content */
- getContent(id: number, page: number) {
- return apiClient.get(
- `/api/ebooks/${id}/content/?page=${page}`,
- );
+ /**
+ * Absolute URL to stream the raw ebook file. The endpoint requires JWT auth,
+ * so callers download it with an Authorization header (e.g. via
+ * expo-file-system) rather than handing the URL to a renderer directly.
+ */
+ getFileUrl(id: number): string {
+ return `${getApiBaseUrl()}/api/books/ebooks/${id}/file/`;
},
-
- /** Update reading progress */
- updateProgress(id: number, data: Partial) {
- return apiClient.patch(
- `/api/ebooks/${id}/progress/`,
- data,
- );
- },
-
- /** Get or update reading settings */
- getSettings(id: number) {
- return apiClient.get(`/api/ebooks/${id}/settings/`);
- },
-
- updateSettings(id: number, data: Partial) {
- return apiClient.patch(
- `/api/ebooks/${id}/settings/`,
- data,
- );
- },
-};
\ No newline at end of file
+};
diff --git a/mobile/src/api/index.ts b/mobile/src/api/index.ts
deleted file mode 100644
index 3ba8646..0000000
--- a/mobile/src/api/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export { apiClient, saveTokens, loadTokens, clearTokens } from "./client";
-export { booksApi } from "./books";
-export { ebooksApi } from "./ebooks";
-export { annotationsApi } from "./annotations";
\ No newline at end of file
diff --git a/mobile/src/api/reader.ts b/mobile/src/api/reader.ts
new file mode 100644
index 0000000..99fd225
--- /dev/null
+++ b/mobile/src/api/reader.ts
@@ -0,0 +1,75 @@
+/**
+ * Reader API client — reading settings and per-book progress.
+ * Mirrors frontend/src/api/reader.ts. Uses the shared axios client so the
+ * JWT access token is attached automatically.
+ */
+
+import api from "./client";
+import type { ReadingProgress, ReadingSettings } from "../types/reader";
+
+export async function getReadingSettings(): Promise {
+ const { data } = await api.get("/api/reader/settings/");
+ return data;
+}
+
+export async function updateReadingSettings(
+ settings: Partial,
+): Promise {
+ const { data } = await api.patch(
+ "/api/reader/settings/",
+ settings,
+ );
+ return data;
+}
+
+interface ProgressWire {
+ current_position: number;
+ last_page: number;
+ epub_location?: string;
+ updated_at?: string;
+}
+
+function toReadingProgress(bookId: number, data: ProgressWire): ReadingProgress {
+ return {
+ id: bookId,
+ book: bookId,
+ current_chapter: data.last_page || 1,
+ current_position: data.current_position ?? 0,
+ percentage: data.current_position ?? 0,
+ epub_location: data.epub_location ?? "",
+ updated_at: data.updated_at ?? "",
+ };
+}
+
+export async function getReadingProgress(
+ bookId: number,
+): Promise {
+ const { data } = await api.get(
+ `/api/books/ebooks/${bookId}/progress/`,
+ );
+ return toReadingProgress(bookId, data);
+}
+
+export async function updateReadingProgress(
+ bookId: number,
+ progress: Partial,
+): Promise {
+ const body: Record = {};
+ if (
+ progress.percentage !== undefined ||
+ progress.current_position !== undefined
+ ) {
+ body.current_position = progress.percentage ?? progress.current_position ?? 0;
+ }
+ if (progress.current_chapter !== undefined) {
+ body.last_page = progress.current_chapter;
+ }
+ if (progress.epub_location !== undefined) {
+ body.epub_location = progress.epub_location;
+ }
+ const { data } = await api.patch(
+ `/api/books/ebooks/${bookId}/progress/`,
+ body,
+ );
+ return toReadingProgress(bookId, data);
+}
diff --git a/mobile/src/components/reader/BookmarksModal.tsx b/mobile/src/components/reader/BookmarksModal.tsx
new file mode 100644
index 0000000..ad79add
--- /dev/null
+++ b/mobile/src/components/reader/BookmarksModal.tsx
@@ -0,0 +1,147 @@
+import { type ReactNode } from "react";
+import {
+ Text,
+ FlatList,
+ TouchableOpacity,
+ StyleSheet,
+ View,
+} from "react-native";
+import { resolvePalette } from "../../utils/epubTheme";
+import type { ReadingSettings } from "../../types/reader";
+import type { Bookmark } from "../../types";
+import { ReaderBottomSheet } from "./ReaderBottomSheet";
+
+interface BookmarksModalProps {
+ visible: boolean;
+ bookmarks: Bookmark[];
+ settings: ReadingSettings;
+ onSelect: (bookmark: Bookmark) => void;
+ onDelete: (bookmark: Bookmark) => void;
+ onClose: () => void;
+}
+
+export function BookmarksModal({
+ visible,
+ bookmarks,
+ settings,
+ onSelect,
+ onDelete,
+ onClose,
+}: BookmarksModalProps): ReactNode {
+ const palette = resolvePalette(settings);
+
+ return (
+
+ item.id}
+ ListEmptyComponent={
+
+ No bookmarks yet. Tap the star to bookmark a page, or select text to
+ highlight it.
+
+ }
+ renderItem={({ item }) => (
+
+ onSelect(item)}
+ >
+ {item.highlight_color ? (
+
+ ) : (
+ ★
+ )}
+
+ {item.chapter_title ? (
+
+ {item.chapter_title}
+
+ ) : null}
+
+ {item.content || item.location_text || "Bookmarked page"}
+
+
+
+ onDelete(item)}
+ hitSlop={8}
+ style={styles.deleteButton}
+ >
+ Delete
+
+
+ )}
+ />
+
+ );
+}
+
+const styles = StyleSheet.create({
+ row: {
+ flexDirection: "row",
+ alignItems: "center",
+ paddingVertical: 12,
+ paddingHorizontal: 16,
+ borderTopWidth: StyleSheet.hairlineWidth,
+ borderTopColor: "rgba(127,127,127,0.2)",
+ },
+ rowMain: {
+ flex: 1,
+ flexDirection: "row",
+ alignItems: "center",
+ },
+ rowTextWrap: {
+ flex: 1,
+ marginLeft: 10,
+ },
+ star: {
+ fontSize: 16,
+ color: "#4f8ef7",
+ },
+ dot: {
+ width: 14,
+ height: 14,
+ borderRadius: 7,
+ },
+ chapter: {
+ fontSize: 12,
+ opacity: 0.7,
+ marginBottom: 2,
+ },
+ excerpt: {
+ fontSize: 14,
+ },
+ deleteButton: {
+ marginLeft: 12,
+ paddingHorizontal: 10,
+ paddingVertical: 6,
+ },
+ deleteText: {
+ color: "#ff453a",
+ fontSize: 13,
+ fontWeight: "600",
+ },
+ empty: {
+ padding: 24,
+ textAlign: "center",
+ opacity: 0.7,
+ },
+});
diff --git a/mobile/src/components/reader/EpubReaderView.tsx b/mobile/src/components/reader/EpubReaderView.tsx
new file mode 100644
index 0000000..85fa1ad
--- /dev/null
+++ b/mobile/src/components/reader/EpubReaderView.tsx
@@ -0,0 +1,436 @@
+import { useCallback, useEffect, useRef, useState, type ReactNode } from "react";
+import {
+ View,
+ Text,
+ ActivityIndicator,
+ StyleSheet,
+ type LayoutChangeEvent,
+} from "react-native";
+import { SafeAreaView } from "react-native-safe-area-context";
+import { Reader, ReaderProvider, useReader } from "@epubjs-react-native/core";
+import { useFileSystem } from "@epubjs-react-native/expo-file-system";
+import * as FileSystem from "expo-file-system";
+import type { EBookDetail } from "@cloud-reader/shared";
+import { getAccessToken } from "../../api/client";
+import { ebooksApi } from "../../api/ebooks";
+import { getReadingProgress, updateReadingProgress } from "../../api/reader";
+import {
+ fetchBookmarks,
+ createMarker,
+ deleteBookmark,
+} from "../../api/annotations";
+import { useReadingSettings } from "../../hooks/useReadingSettings";
+import {
+ buildEpubTheme,
+ FONT_STACKS,
+ resolvePalette,
+} from "../../utils/epubTheme";
+import type { Bookmark } from "../../types";
+import { ReaderToolbar } from "./ReaderToolbar";
+import { TocModal, type TocItem } from "./TocModal";
+import { ReadingSettingsModal } from "./ReadingSettingsModal";
+import { BookmarksModal } from "./BookmarksModal";
+
+const HIGHLIGHT_COLOR = "#ffd54a";
+const PROGRESS_SAVE_MS = 800;
+
+/** Loose view of the epubjs-react-native reader API we rely on. */
+interface ReaderApi {
+ goToLocation?: (target: string) => void;
+ changeTheme?: (theme: Record>) => void;
+ changeFontSize?: (size: string) => void;
+ changeFontFamily?: (font: string) => void;
+ addAnnotation?: (
+ type: string,
+ cfiRange: string,
+ data?: unknown,
+ styles?: Record,
+ ) => void;
+ removeAnnotationByCfi?: (cfi: string) => void;
+ removeSelection?: () => void;
+ toc?: TocItem[];
+}
+
+interface EpubLocation {
+ start?: { cfi?: string };
+}
+
+interface EpubSection {
+ label?: string;
+ index?: number;
+}
+
+interface EpubReaderViewProps {
+ book: EBookDetail;
+ ebookId: number;
+ onClose: () => void;
+}
+
+export function EpubReaderView(props: EpubReaderViewProps): ReactNode {
+ return (
+
+
+
+ );
+}
+
+function EpubReaderInner({
+ book,
+ ebookId,
+ onClose,
+}: EpubReaderViewProps): ReactNode {
+ const reader = useReader() as unknown as ReaderApi;
+ const { settings, updateSettings } = useReadingSettings();
+
+ const [src, setSrc] = useState(null);
+ const [initialLocation, setInitialLocation] = useState();
+ const [fileError, setFileError] = useState(false);
+ const [ready, setReady] = useState(false);
+ const [size, setSize] = useState<{ width: number; height: number } | null>(
+ null,
+ );
+
+ const [progressPct, setProgressPct] = useState(
+ Math.round(book.progress?.current_position ?? 0),
+ );
+ const [chapterTitle, setChapterTitle] = useState("");
+ const [currentCfi, setCurrentCfi] = useState("");
+ const [bookmarks, setBookmarks] = useState([]);
+
+ const [tocOpen, setTocOpen] = useState(false);
+ const [settingsOpen, setSettingsOpen] = useState(false);
+ const [bookmarksOpen, setBookmarksOpen] = useState(false);
+
+ const currentCfiRef = useRef("");
+ const progressPctRef = useRef(progressPct);
+ const sectionRef = useRef<{ index: number; label: string }>({
+ index: 0,
+ label: "",
+ });
+ const bookmarksRef = useRef([]);
+ const saveTimerRef = useRef | null>(null);
+
+ useEffect(() => {
+ bookmarksRef.current = bookmarks;
+ }, [bookmarks]);
+
+ // Download the EPUB with auth, and resolve the saved resume location.
+ useEffect(() => {
+ let active = true;
+ (async () => {
+ try {
+ const progress = await getReadingProgress(ebookId).catch(() => null);
+ if (active && progress?.epub_location) {
+ setInitialLocation(progress.epub_location);
+ currentCfiRef.current = progress.epub_location;
+ setCurrentCfi(progress.epub_location);
+ }
+ const token = await getAccessToken();
+ const url = ebooksApi.getFileUrl(ebookId);
+ const dest = `${FileSystem.cacheDirectory}ebook-${ebookId}.epub`;
+ const result = await FileSystem.downloadAsync(url, dest, {
+ headers: token ? { Authorization: `Bearer ${token}` } : undefined,
+ });
+ if (!active) return;
+ if (result.status >= 400) {
+ setFileError(true);
+ return;
+ }
+ setSrc(result.uri);
+ } catch {
+ if (active) setFileError(true);
+ }
+ })();
+ return () => {
+ active = false;
+ };
+ }, [ebookId]);
+
+ // Load existing bookmarks/highlights for this book.
+ useEffect(() => {
+ let active = true;
+ fetchBookmarks(ebookId)
+ .then((res) => {
+ if (active) setBookmarks(res.results);
+ })
+ .catch(() => {
+ /* bookmarks are optional */
+ });
+ return () => {
+ active = false;
+ };
+ }, [ebookId]);
+
+ // Apply typography/theme to the rendition once it is ready and on changes.
+ useEffect(() => {
+ if (!ready) return;
+ try {
+ reader.changeTheme?.(buildEpubTheme(settings));
+ reader.changeFontSize?.(`${settings.font_size}px`);
+ reader.changeFontFamily?.(FONT_STACKS[settings.font_family]);
+ } catch {
+ /* ignore rendition styling errors */
+ }
+ }, [ready, settings, reader]);
+
+ const flushProgress = useCallback(() => {
+ const cfi = currentCfiRef.current;
+ if (!cfi) return;
+ updateReadingProgress(ebookId, {
+ percentage: progressPctRef.current,
+ epub_location: cfi,
+ current_chapter: sectionRef.current.index + 1,
+ }).catch(() => {
+ /* progress is best-effort */
+ });
+ }, [ebookId]);
+
+ // Flush the latest progress when leaving the reader.
+ useEffect(
+ () => () => {
+ if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
+ flushProgress();
+ },
+ [flushProgress],
+ );
+
+ const handleReady = useCallback(() => {
+ setReady(true);
+ bookmarksRef.current.forEach((bookmark) => {
+ if (bookmark.highlight_color && bookmark.epub_cfi) {
+ try {
+ reader.addAnnotation?.("highlight", bookmark.epub_cfi, undefined, {
+ fill: bookmark.highlight_color,
+ });
+ } catch {
+ /* highlight rendering is best-effort */
+ }
+ }
+ });
+ }, [reader]);
+
+ const handleLocationChange = useCallback(
+ (
+ _total: number,
+ location: EpubLocation,
+ progress: number,
+ section: EpubSection | null,
+ ) => {
+ const cfi = location?.start?.cfi ?? "";
+ if (cfi) {
+ currentCfiRef.current = cfi;
+ setCurrentCfi(cfi);
+ }
+ const pct = Math.round(progress ?? 0);
+ progressPctRef.current = pct;
+ setProgressPct(pct);
+ const label = section?.label?.trim() ?? "";
+ sectionRef.current = {
+ index: section?.index ?? sectionRef.current.index,
+ label,
+ };
+ setChapterTitle(label);
+
+ if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
+ saveTimerRef.current = setTimeout(flushProgress, PROGRESS_SAVE_MS);
+ },
+ [flushProgress],
+ );
+
+ const handleSelected = useCallback(
+ async (selectedText: string, cfiRange: string) => {
+ const excerpt = (selectedText ?? "").slice(0, 280);
+ try {
+ const created = await createMarker({
+ ebook: ebookId,
+ epub_cfi: cfiRange,
+ chapter_index: sectionRef.current.index,
+ chapter_title: sectionRef.current.label,
+ location_text: excerpt,
+ content: excerpt,
+ highlight_color: HIGHLIGHT_COLOR,
+ });
+ setBookmarks((prev) => [created, ...prev]);
+ try {
+ reader.addAnnotation?.("highlight", cfiRange, undefined, {
+ fill: HIGHLIGHT_COLOR,
+ });
+ reader.removeSelection?.();
+ } catch {
+ /* annotation rendering is best-effort */
+ }
+ } catch {
+ /* ignore highlight save failures */
+ }
+ },
+ [ebookId, reader],
+ );
+
+ const handleToggleBookmarkHere = useCallback(async () => {
+ const cfi = currentCfiRef.current;
+ if (!cfi) return;
+ const existing = bookmarksRef.current.find((b) => b.epub_cfi === cfi);
+ if (existing) {
+ setBookmarks((prev) => prev.filter((b) => b.id !== existing.id));
+ try {
+ reader.removeAnnotationByCfi?.(cfi);
+ } catch {
+ /* best-effort */
+ }
+ deleteBookmark(existing.id).catch(() => {});
+ return;
+ }
+ try {
+ const created = await createMarker({
+ ebook: ebookId,
+ epub_cfi: cfi,
+ chapter_index: sectionRef.current.index,
+ chapter_title: sectionRef.current.label,
+ location_text: sectionRef.current.label,
+ });
+ setBookmarks((prev) => [created, ...prev]);
+ } catch {
+ /* ignore bookmark save failures */
+ }
+ }, [ebookId, reader]);
+
+ const handleSelectBookmark = useCallback(
+ (bookmark: Bookmark) => {
+ setBookmarksOpen(false);
+ try {
+ reader.goToLocation?.(bookmark.epub_cfi);
+ } catch {
+ /* best-effort */
+ }
+ },
+ [reader],
+ );
+
+ const handleDeleteBookmark = useCallback(
+ (bookmark: Bookmark) => {
+ setBookmarks((prev) => prev.filter((b) => b.id !== bookmark.id));
+ try {
+ if (bookmark.highlight_color) {
+ reader.removeAnnotationByCfi?.(bookmark.epub_cfi);
+ }
+ } catch {
+ /* best-effort */
+ }
+ deleteBookmark(bookmark.id).catch(() => {});
+ },
+ [reader],
+ );
+
+ const handleTocSelect = useCallback(
+ (href: string) => {
+ setTocOpen(false);
+ try {
+ reader.goToLocation?.(href);
+ } catch {
+ /* best-effort */
+ }
+ },
+ [reader],
+ );
+
+ const onReaderLayout = useCallback((event: LayoutChangeEvent) => {
+ const { width, height } = event.nativeEvent.layout;
+ setSize((prev) =>
+ prev && prev.width === width && prev.height === height
+ ? prev
+ : { width, height },
+ );
+ }, []);
+
+ const palette = resolvePalette(settings);
+ const isBookmarked = bookmarks.some((b) => b.epub_cfi === currentCfi);
+
+ return (
+
+ setTocOpen(true)}
+ onToggleSettings={() => setSettingsOpen(true)}
+ onToggleBookmarks={() => setBookmarksOpen(true)}
+ onToggleBookmarkHere={handleToggleBookmarkHere}
+ />
+
+
+ {fileError ? (
+
+
+ Could not download this book. Check your connection and try again.
+
+
+ ) : src && size ? (
+
+ ) : (
+
+
+
+ )}
+
+
+ setTocOpen(false)}
+ />
+ setSettingsOpen(false)}
+ />
+ setBookmarksOpen(false)}
+ />
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ readerArea: {
+ flex: 1,
+ },
+ centered: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ padding: 24,
+ },
+ message: {
+ fontSize: 15,
+ textAlign: "center",
+ },
+});
diff --git a/mobile/src/components/reader/ReaderBottomSheet.tsx b/mobile/src/components/reader/ReaderBottomSheet.tsx
new file mode 100644
index 0000000..6e8538b
--- /dev/null
+++ b/mobile/src/components/reader/ReaderBottomSheet.tsx
@@ -0,0 +1,92 @@
+import { type ReactNode } from "react";
+import {
+ Modal,
+ View,
+ Text,
+ TouchableOpacity,
+ StyleSheet,
+ type StyleProp,
+ type ViewStyle,
+} from "react-native";
+
+interface ReaderBottomSheetProps {
+ visible: boolean;
+ title: string;
+ chromeColor: string;
+ textColor: string;
+ onClose: () => void;
+ children: ReactNode;
+ /** When true, caps sheet height (TOC/bookmarks). Settings uses a full-width panel. */
+ tall?: boolean;
+ sheetStyle?: StyleProp;
+}
+
+export function ReaderBottomSheet({
+ visible,
+ title,
+ chromeColor,
+ textColor,
+ onClose,
+ children,
+ tall = true,
+ sheetStyle,
+}: ReaderBottomSheetProps): ReactNode {
+ return (
+
+
+
+
+
+ {title}
+
+
+ ✕
+
+
+ {children}
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ backdrop: {
+ flex: 1,
+ backgroundColor: "rgba(0,0,0,0.4)",
+ justifyContent: "flex-end",
+ },
+ sheet: {
+ borderTopLeftRadius: 16,
+ borderTopRightRadius: 16,
+ paddingBottom: 24,
+ },
+ sheetTall: {
+ maxHeight: "75%",
+ },
+ header: {
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ padding: 16,
+ },
+ headerTitle: {
+ fontSize: 16,
+ fontWeight: "700",
+ },
+ close: {
+ fontSize: 18,
+ },
+});
diff --git a/mobile/src/components/reader/ReaderToolbar.tsx b/mobile/src/components/reader/ReaderToolbar.tsx
new file mode 100644
index 0000000..3cce9ee
--- /dev/null
+++ b/mobile/src/components/reader/ReaderToolbar.tsx
@@ -0,0 +1,152 @@
+import { type ReactNode } from "react";
+import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
+import { resolvePalette } from "../../utils/epubTheme";
+import type { ReadingSettings } from "../../types/reader";
+
+interface ReaderToolbarProps {
+ title: string;
+ chapterTitle: string;
+ progressPct: number;
+ settings: ReadingSettings;
+ isBookmarked: boolean;
+ onBack: () => void;
+ onToggleToc: () => void;
+ onToggleSettings: () => void;
+ onToggleBookmarks: () => void;
+ onToggleBookmarkHere: () => void;
+}
+
+export function ReaderToolbar({
+ title,
+ chapterTitle,
+ progressPct,
+ settings,
+ isBookmarked,
+ onBack,
+ onToggleToc,
+ onToggleSettings,
+ onToggleBookmarks,
+ onToggleBookmarkHere,
+}: ReaderToolbarProps): ReactNode {
+ const palette = resolvePalette(settings);
+
+ return (
+
+
+
+ ‹
+
+
+
+
+ {title}
+
+ {chapterTitle ? (
+
+ {chapterTitle}
+
+ ) : null}
+
+
+
+
+ {isBookmarked ? "★" : "☆"}
+
+
+
+ ≡
+
+
+ ⊟
+
+
+ Aa
+
+
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ bar: {
+ paddingTop: 8,
+ paddingHorizontal: 8,
+ paddingBottom: 6,
+ },
+ row: {
+ flexDirection: "row",
+ alignItems: "center",
+ },
+ titles: {
+ flex: 1,
+ marginHorizontal: 8,
+ },
+ title: {
+ fontSize: 14,
+ fontWeight: "600",
+ },
+ chapter: {
+ fontSize: 11,
+ opacity: 0.7,
+ },
+ iconButton: {
+ paddingHorizontal: 8,
+ paddingVertical: 4,
+ minWidth: 28,
+ alignItems: "center",
+ },
+ icon: {
+ fontSize: 28,
+ lineHeight: 30,
+ },
+ iconSmall: {
+ fontSize: 17,
+ fontWeight: "600",
+ },
+ progressTrack: {
+ height: 3,
+ borderRadius: 2,
+ backgroundColor: "rgba(127,127,127,0.25)",
+ marginTop: 6,
+ overflow: "hidden",
+ },
+ progressFill: {
+ height: "100%",
+ backgroundColor: "#4f8ef7",
+ },
+});
diff --git a/mobile/src/components/reader/ReadingSettingsModal.tsx b/mobile/src/components/reader/ReadingSettingsModal.tsx
new file mode 100644
index 0000000..b789fad
--- /dev/null
+++ b/mobile/src/components/reader/ReadingSettingsModal.tsx
@@ -0,0 +1,249 @@
+import { type ReactNode } from "react";
+import {
+ View,
+ Text,
+ TouchableOpacity,
+ StyleSheet,
+} from "react-native";
+import { resolvePalette, THEME_PALETTES } from "../../utils/epubTheme";
+import type {
+ FontFamily,
+ ReadingSettings,
+ ThemePreset,
+} from "../../types/reader";
+import { ReaderBottomSheet } from "./ReaderBottomSheet";
+
+const THEMES: ThemePreset[] = ["light", "sepia", "paper", "dark"];
+const FONTS: { value: FontFamily; label: string }[] = [
+ { value: "serif", label: "Serif" },
+ { value: "sans-serif", label: "Sans" },
+ { value: "monospace", label: "Mono" },
+];
+const FONT_SIZE_MIN = 12;
+const FONT_SIZE_MAX = 32;
+const LINE_HEIGHT_MIN = 1.2;
+const LINE_HEIGHT_MAX = 2.2;
+
+interface ReadingSettingsModalProps {
+ visible: boolean;
+ settings: ReadingSettings;
+ onChange: (patch: Partial) => void;
+ onClose: () => void;
+}
+
+export function ReadingSettingsModal({
+ visible,
+ settings,
+ onChange,
+ onClose,
+}: ReadingSettingsModalProps): ReactNode {
+ const palette = resolvePalette(settings);
+
+ const adjustFontSize = (delta: number) => {
+ const next = Math.min(
+ FONT_SIZE_MAX,
+ Math.max(FONT_SIZE_MIN, settings.font_size + delta),
+ );
+ onChange({ font_size: next });
+ };
+
+ const adjustLineHeight = (delta: number) => {
+ const next = Math.min(
+ LINE_HEIGHT_MAX,
+ Math.max(
+ LINE_HEIGHT_MIN,
+ Math.round((settings.line_height + delta) * 10) / 10,
+ ),
+ );
+ onChange({ line_height: next });
+ };
+
+ return (
+
+ Theme
+
+ {THEMES.map((theme) => {
+ const p = THEME_PALETTES[theme];
+ const active = settings.theme === theme;
+ return (
+
+ onChange({
+ theme,
+ background_color: p.background,
+ text_color: p.text,
+ })
+ }
+ style={[
+ styles.themeSwatch,
+ { backgroundColor: p.background },
+ active && styles.themeSwatchActive,
+ ]}
+ >
+
+ Aa
+
+
+ );
+ })}
+
+
+ Font
+
+ {FONTS.map((font) => {
+ const active = settings.font_family === font.value;
+ return (
+ onChange({ font_family: font.value })}
+ style={[styles.pill, active && styles.pillActive]}
+ >
+
+ {font.label}
+
+
+ );
+ })}
+
+
+ adjustFontSize(-1)}
+ onIncrease={() => adjustFontSize(1)}
+ />
+ adjustLineHeight(-0.1)}
+ onIncrease={() => adjustLineHeight(0.1)}
+ />
+
+ );
+}
+
+function Stepper({
+ label,
+ value,
+ color,
+ onDecrease,
+ onIncrease,
+}: {
+ label: string;
+ value: string;
+ color: string;
+ onDecrease: () => void;
+ onIncrease: () => void;
+}): ReactNode {
+ return (
+
+
+ {label}
+
+
+
+ −
+
+ {value}
+
+ +
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ sheetBody: {
+ paddingHorizontal: 20,
+ paddingBottom: 32,
+ },
+ sectionLabel: {
+ fontSize: 13,
+ fontWeight: "600",
+ marginBottom: 8,
+ marginTop: 8,
+ opacity: 0.8,
+ },
+ rowWrap: {
+ flexDirection: "row",
+ flexWrap: "wrap",
+ gap: 10,
+ },
+ themeSwatch: {
+ width: 56,
+ height: 48,
+ borderRadius: 10,
+ justifyContent: "center",
+ alignItems: "center",
+ borderWidth: 2,
+ borderColor: "transparent",
+ },
+ themeSwatchActive: {
+ borderColor: "#4f8ef7",
+ },
+ themeSwatchText: {
+ fontSize: 16,
+ fontWeight: "600",
+ },
+ pill: {
+ paddingHorizontal: 16,
+ paddingVertical: 8,
+ borderRadius: 20,
+ borderWidth: 1,
+ borderColor: "rgba(127,127,127,0.4)",
+ },
+ pillActive: {
+ backgroundColor: "#4f8ef7",
+ borderColor: "#4f8ef7",
+ },
+ pillText: {
+ fontSize: 14,
+ fontWeight: "600",
+ },
+ stepperRow: {
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ marginTop: 16,
+ },
+ stepperControls: {
+ flexDirection: "row",
+ alignItems: "center",
+ },
+ stepperButton: {
+ width: 36,
+ height: 36,
+ borderRadius: 18,
+ backgroundColor: "rgba(127,127,127,0.2)",
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ stepperButtonText: {
+ fontSize: 20,
+ fontWeight: "700",
+ color: "#4f8ef7",
+ },
+ stepperValue: {
+ minWidth: 56,
+ textAlign: "center",
+ fontSize: 15,
+ fontWeight: "600",
+ },
+});
diff --git a/mobile/src/components/reader/TocModal.tsx b/mobile/src/components/reader/TocModal.tsx
new file mode 100644
index 0000000..7028c55
--- /dev/null
+++ b/mobile/src/components/reader/TocModal.tsx
@@ -0,0 +1,111 @@
+import { type ReactNode } from "react";
+import {
+ Text,
+ FlatList,
+ TouchableOpacity,
+ StyleSheet,
+} from "react-native";
+import { resolvePalette } from "../../utils/epubTheme";
+import type { ReadingSettings } from "../../types/reader";
+import { ReaderBottomSheet } from "./ReaderBottomSheet";
+
+export interface TocItem {
+ id?: string;
+ label: string;
+ href: string;
+ subitems?: TocItem[];
+}
+
+interface FlatTocItem {
+ key: string;
+ label: string;
+ href: string;
+ depth: number;
+}
+
+function flatten(items: TocItem[], depth = 0, acc: FlatTocItem[] = []) {
+ items.forEach((item, index) => {
+ acc.push({
+ key: `${item.id ?? item.href}-${depth}-${index}`,
+ label: (item.label ?? "").trim() || "Untitled section",
+ href: item.href,
+ depth,
+ });
+ if (item.subitems?.length) {
+ flatten(item.subitems, depth + 1, acc);
+ }
+ });
+ return acc;
+}
+
+interface TocModalProps {
+ visible: boolean;
+ toc: TocItem[];
+ settings: ReadingSettings;
+ onSelect: (href: string) => void;
+ onClose: () => void;
+}
+
+export function TocModal({
+ visible,
+ toc,
+ settings,
+ onSelect,
+ onClose,
+}: TocModalProps): ReactNode {
+ const palette = resolvePalette(settings);
+ const data = flatten(toc);
+
+ return (
+
+ item.key}
+ ListEmptyComponent={
+
+ No table of contents available.
+
+ }
+ renderItem={({ item }) => (
+ onSelect(item.href)}
+ >
+
+ {item.label}
+
+
+ )}
+ />
+
+ );
+}
+
+const styles = StyleSheet.create({
+ row: {
+ paddingVertical: 12,
+ paddingHorizontal: 16,
+ borderTopWidth: StyleSheet.hairlineWidth,
+ borderTopColor: "rgba(127,127,127,0.2)",
+ },
+ rowText: {
+ fontSize: 14,
+ },
+ empty: {
+ padding: 24,
+ textAlign: "center",
+ opacity: 0.7,
+ },
+});
diff --git a/mobile/src/hooks/index.ts b/mobile/src/hooks/index.ts
deleted file mode 100644
index b751c47..0000000
--- a/mobile/src/hooks/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { useAuth } from "../context/AuthContext";
-export { useAsyncData } from "./useAsyncData";
\ No newline at end of file
diff --git a/mobile/src/hooks/useAsyncData.ts b/mobile/src/hooks/useAsyncData.ts
deleted file mode 100644
index 3f57c37..0000000
--- a/mobile/src/hooks/useAsyncData.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { useState, useEffect, useCallback } from "react";
-
-/**
- * Generic async data fetching hook for mobile screens.
- */
-export function useAsyncData(
- fetcher: () => Promise,
- deps: unknown[] = [],
-) {
- const [data, setData] = useState(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- const execute = useCallback(async () => {
- setLoading(true);
- setError(null);
- try {
- const result = await fetcher();
- setData(result);
- } catch (err) {
- setError(err instanceof Error ? err : new Error(String(err)));
- } finally {
- setLoading(false);
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, deps);
-
- useEffect(() => {
- execute();
- }, [execute]);
-
- return { data, loading, error, refetch: execute };
-}
\ No newline at end of file
diff --git a/mobile/src/hooks/useReadingSettings.ts b/mobile/src/hooks/useReadingSettings.ts
new file mode 100644
index 0000000..ce72a8a
--- /dev/null
+++ b/mobile/src/hooks/useReadingSettings.ts
@@ -0,0 +1,82 @@
+import { useCallback, useEffect, useRef, useState } from "react";
+import {
+ getReadingSettings,
+ updateReadingSettings,
+} from "../api/reader";
+import type { ReadingSettings } from "../types/reader";
+
+const DEFAULT_READING_SETTINGS: ReadingSettings = {
+ font_family: "serif",
+ font_size: 18,
+ line_height: 1.5,
+ margin_width: 16,
+ background_color: "#fbfbf8",
+ text_color: "#2b2b2b",
+ brightness: 1,
+ orientation_lock: "auto",
+ theme: "paper",
+ created_at: "",
+ updated_at: "",
+};
+
+const SAVE_DEBOUNCE_MS = 600;
+
+interface UseReadingSettingsReturn {
+ settings: ReadingSettings;
+ loaded: boolean;
+ updateSettings: (patch: Partial) => void;
+}
+
+/**
+ * Loads the user's reader settings and persists changes with a debounce.
+ * Mirrors frontend/src/hooks/useReadingSettings.ts behavior.
+ */
+export function useReadingSettings(): UseReadingSettingsReturn {
+ const [settings, setSettings] = useState(
+ DEFAULT_READING_SETTINGS,
+ );
+ const [loaded, setLoaded] = useState(false);
+ const pendingRef = useRef>({});
+ const timerRef = useRef | null>(null);
+
+ useEffect(() => {
+ let active = true;
+ getReadingSettings()
+ .then((data) => {
+ if (active) {
+ setSettings(data);
+ }
+ })
+ .catch(() => {
+ /* keep defaults if the request fails */
+ })
+ .finally(() => {
+ if (active) {
+ setLoaded(true);
+ }
+ });
+ return () => {
+ active = false;
+ if (timerRef.current) {
+ clearTimeout(timerRef.current);
+ }
+ };
+ }, []);
+
+ const updateSettings = useCallback((patch: Partial) => {
+ setSettings((prev) => ({ ...prev, ...patch }));
+ pendingRef.current = { ...pendingRef.current, ...patch };
+ if (timerRef.current) {
+ clearTimeout(timerRef.current);
+ }
+ timerRef.current = setTimeout(() => {
+ const body = pendingRef.current;
+ pendingRef.current = {};
+ updateReadingSettings(body).catch(() => {
+ /* ignore transient save failures */
+ });
+ }, SAVE_DEBOUNCE_MS);
+ }, []);
+
+ return { settings, loaded, updateSettings };
+}
diff --git a/mobile/src/navigation/AppNavigator.tsx b/mobile/src/navigation/AppNavigator.tsx
deleted file mode 100644
index d64e751..0000000
--- a/mobile/src/navigation/AppNavigator.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { type ReactNode } from "react";
-import { NavigationContainer } from "@react-navigation/native";
-import { createNativeStackNavigator } from "@react-navigation/native-stack";
-import { useAuth } from "../context/AuthContext";
-import LoginScreen from "../screens/LoginScreen";
-import RegisterScreen from "../screens/RegisterScreen";
-import MainTabs from "./MainTabs";
-
-export type AuthStackParamList = {
- Login: undefined;
- Register: undefined;
-};
-
-export type RootStackParamList = {
- Auth: undefined;
- Main: undefined;
-};
-
-const RootStack = createNativeStackNavigator();
-const AuthStack = createNativeStackNavigator();
-
-function AuthNavigator(): ReactNode {
- return (
-
-
-
-
- );
-}
-
-export default function AppNavigator(): ReactNode {
- const { state } = useAuth();
-
- return (
-
-
- {state.isAuthenticated ? (
-
- ) : (
-
- )}
-
-
- );
-}
\ No newline at end of file
diff --git a/mobile/src/navigation/AppStack.tsx b/mobile/src/navigation/AppStack.tsx
new file mode 100644
index 0000000..f90cda6
--- /dev/null
+++ b/mobile/src/navigation/AppStack.tsx
@@ -0,0 +1,36 @@
+import React from "react";
+import { createNativeStackNavigator } from "@react-navigation/native-stack";
+import { MainNavigator } from "./MainNavigator";
+import BookDetailScreen from "../screens/BookDetailScreen";
+import ReaderScreen from "../screens/ReaderScreen";
+import type { AppStackParamList } from "../types";
+
+const Stack = createNativeStackNavigator();
+
+export function AppStack() {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/mobile/src/navigation/AuthNavigator.tsx b/mobile/src/navigation/AuthNavigator.tsx
index 697e99f..b8601c3 100644
--- a/mobile/src/navigation/AuthNavigator.tsx
+++ b/mobile/src/navigation/AuthNavigator.tsx
@@ -3,7 +3,7 @@ import { createNativeStackNavigator } from "@react-navigation/native-stack";
import LoginScreen from "../screens/LoginScreen";
import RegisterScreen from "../screens/RegisterScreen";
-export type AuthStackParamList = {
+type AuthStackParamList = {
Login: undefined;
Register: undefined;
};
diff --git a/mobile/src/navigation/MainTabs.tsx b/mobile/src/navigation/MainTabs.tsx
deleted file mode 100644
index 9f80e33..0000000
--- a/mobile/src/navigation/MainTabs.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import { type ReactNode } from "react";
-import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
-import { Text } from "react-native";
-import LibraryScreen from "../screens/LibraryScreen";
-import SearchScreen from "../screens/SearchScreen";
-import SettingsScreen from "../screens/SettingsScreen";
-
-export type MainTabParamList = {
- Library: undefined;
- Search: undefined;
- Settings: undefined;
-};
-
-const Tab = createBottomTabNavigator();
-
-function TabIcon({ label, focused }: { label: string; focused: boolean }) {
- return (
-
- {label === "Library" ? "📚" : label === "Search" ? "🔍" : "⚙️"}
-
- );
-}
-
-export default function MainTabs(): ReactNode {
- return (
- ({
- tabBarIcon: ({ focused }: { focused: boolean }) => (
-
- ),
- tabBarActiveTintColor: "#4f8ef7",
- tabBarInactiveTintColor: "#888",
- headerStyle: { backgroundColor: "#1a1a2e" },
- headerTintColor: "#fff",
- tabBarStyle: { backgroundColor: "#1a1a2e", borderTopColor: "#333" },
- })}
- >
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/mobile/src/navigation/RootNavigator.tsx b/mobile/src/navigation/RootNavigator.tsx
index b857e50..7274c9d 100644
--- a/mobile/src/navigation/RootNavigator.tsx
+++ b/mobile/src/navigation/RootNavigator.tsx
@@ -2,7 +2,7 @@ import React from "react";
import { ActivityIndicator, View } from "react-native";
import { useAuth } from "../context/AuthContext";
import { AuthNavigator } from "./AuthNavigator";
-import { MainNavigator } from "./MainNavigator";
+import { AppStack } from "./AppStack";
export function RootNavigator() {
const { isLoading, isAuthenticated } = useAuth();
@@ -19,5 +19,5 @@ export function RootNavigator() {
return ;
}
- return ;
+ return ;
}
\ No newline at end of file
diff --git a/mobile/src/screens/AuthFormError.tsx b/mobile/src/screens/AuthFormError.tsx
new file mode 100644
index 0000000..31eee5c
--- /dev/null
+++ b/mobile/src/screens/AuthFormError.tsx
@@ -0,0 +1,11 @@
+import { type ReactNode } from "react";
+import { View, Text } from "react-native";
+import { authStyles } from "./authStyles";
+
+export function AuthFormError({ message }: { message: string }): ReactNode {
+ return (
+
+ {message}
+
+ );
+}
diff --git a/mobile/src/screens/BookDetailScreen.tsx b/mobile/src/screens/BookDetailScreen.tsx
new file mode 100644
index 0000000..4cea681
--- /dev/null
+++ b/mobile/src/screens/BookDetailScreen.tsx
@@ -0,0 +1,226 @@
+import { useState, useEffect, useCallback, type ReactNode } from "react";
+import {
+ View,
+ Text,
+ Image,
+ ScrollView,
+ TouchableOpacity,
+ StyleSheet,
+ ActivityIndicator,
+} from "react-native";
+import type { RouteProp } from "@react-navigation/native";
+import { ebooksApi } from "../api/ebooks";
+import { formatFileSize } from "@cloud-reader/shared";
+import type { EBookDetail } from "@cloud-reader/shared";
+import type { AppStackParamList } from "../types";
+
+type DetailRoute = RouteProp;
+
+export default function BookDetailScreen({
+ route,
+ navigation,
+}: {
+ route: DetailRoute;
+ navigation: any;
+}): ReactNode {
+ const { ebookId } = route.params;
+ const [book, setBook] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(false);
+
+ const load = useCallback(async () => {
+ try {
+ const { data } = await ebooksApi.get(ebookId);
+ setBook(data);
+ } catch {
+ setError(true);
+ } finally {
+ setLoading(false);
+ }
+ }, [ebookId]);
+
+ useEffect(() => {
+ load();
+ }, [load]);
+
+ if (loading) {
+ return (
+
+
+
+ );
+ }
+
+ if (error || !book) {
+ return (
+
+ Could not load this book.
+
+ );
+ }
+
+ const progressPct =
+ typeof book.progress?.current_position === "number"
+ ? Math.round(book.progress.current_position)
+ : 0;
+ const hasProgress = progressPct > 0;
+
+ return (
+
+
+ {book.cover_image ? (
+
+ ) : (
+
+
+ {book.title.charAt(0).toUpperCase()}
+
+
+ )}
+ {book.title}
+ {book.author || "Unknown author"}
+
+
+
+
+
+
+
+
+ {hasProgress && (
+
+
+
+
+ {progressPct}% read
+
+ )}
+
+ navigation.navigate("Reader", { ebookId: book.id })}
+ >
+
+ {hasProgress ? "Resume reading" : "Start reading"}
+
+
+
+ );
+}
+
+function MetaPill({ label, value }: { label: string; value: string }): ReactNode {
+ return (
+
+ {value}
+ {label}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: "#0f0f23",
+ },
+ content: {
+ padding: 24,
+ },
+ centered: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ backgroundColor: "#0f0f23",
+ padding: 24,
+ },
+ header: {
+ alignItems: "center",
+ marginBottom: 24,
+ },
+ cover: {
+ width: 140,
+ height: 200,
+ borderRadius: 12,
+ backgroundColor: "#2a2a4e",
+ justifyContent: "center",
+ alignItems: "center",
+ marginBottom: 16,
+ },
+ coverText: {
+ fontSize: 56,
+ fontWeight: "bold",
+ color: "#4f8ef7",
+ },
+ title: {
+ fontSize: 22,
+ fontWeight: "700",
+ color: "#fff",
+ textAlign: "center",
+ marginBottom: 6,
+ },
+ author: {
+ fontSize: 15,
+ color: "#888",
+ textAlign: "center",
+ },
+ metaRow: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ marginBottom: 24,
+ },
+ metaPill: {
+ flex: 1,
+ backgroundColor: "#1a1a2e",
+ borderRadius: 10,
+ paddingVertical: 12,
+ marginHorizontal: 4,
+ alignItems: "center",
+ borderWidth: 1,
+ borderColor: "#333",
+ },
+ metaValue: {
+ fontSize: 15,
+ fontWeight: "600",
+ color: "#fff",
+ },
+ metaLabel: {
+ fontSize: 12,
+ color: "#666",
+ marginTop: 2,
+ },
+ progressWrap: {
+ marginBottom: 24,
+ },
+ progressTrack: {
+ height: 6,
+ borderRadius: 3,
+ backgroundColor: "#1a1a2e",
+ overflow: "hidden",
+ },
+ progressFill: {
+ height: "100%",
+ backgroundColor: "#4f8ef7",
+ },
+ progressLabel: {
+ fontSize: 12,
+ color: "#888",
+ marginTop: 6,
+ },
+ readButton: {
+ backgroundColor: "#4f8ef7",
+ borderRadius: 10,
+ paddingVertical: 16,
+ alignItems: "center",
+ },
+ readButtonText: {
+ color: "#fff",
+ fontSize: 16,
+ fontWeight: "600",
+ },
+ errorText: {
+ color: "#888",
+ fontSize: 15,
+ },
+});
diff --git a/mobile/src/screens/LibraryScreen.tsx b/mobile/src/screens/LibraryScreen.tsx
index 6f10d13..a481b8e 100644
--- a/mobile/src/screens/LibraryScreen.tsx
+++ b/mobile/src/screens/LibraryScreen.tsx
@@ -2,34 +2,31 @@ import { useState, useEffect, useCallback, type ReactNode } from "react";
import {
View,
Text,
+ Image,
FlatList,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
RefreshControl,
} from "react-native";
-import { fetchBooks } from "../api/books";
-import type { Book, PaginatedResponse } from "@cloud-reader/shared";
+import { ebooksApi } from "../api/ebooks";
+import type { EBookListItem } from "@cloud-reader/shared";
-export default function LibraryScreen({ navigation }: { navigation: any }): ReactNode {
- const [books, setBooks] = useState([]);
+export default function LibraryScreen({
+ navigation,
+}: {
+ navigation: any;
+}): ReactNode {
+ const [books, setBooks] = useState([]);
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
- const [page, setPage] = useState(1);
- const [hasMore, setHasMore] = useState(true);
- const loadBooks = useCallback(async (pageNum: number, isRefresh = false) => {
+ const loadBooks = useCallback(async () => {
try {
- const data: PaginatedResponse = await fetchBooks(pageNum);
- if (isRefresh) {
- setBooks(data.results);
- } else {
- setBooks((prev) => [...prev, ...data.results]);
- }
- setHasMore(data.next !== null);
- setPage(pageNum);
+ const { data } = await ebooksApi.list();
+ setBooks(data.results);
} catch {
- // Silent error for now
+ // Silent error for now; pull-to-refresh lets the user retry.
} finally {
setLoading(false);
setRefreshing(false);
@@ -37,44 +34,49 @@ export default function LibraryScreen({ navigation }: { navigation: any }): Reac
}, []);
useEffect(() => {
- loadBooks(1, true);
+ loadBooks();
}, [loadBooks]);
const onRefresh = () => {
setRefreshing(true);
- loadBooks(1, true);
+ loadBooks();
};
- const loadMore = () => {
- if (hasMore && !loading) {
- loadBooks(page + 1);
- }
+ const renderBook = ({ item }: { item: EBookListItem }) => {
+ const progress =
+ typeof item.progress === "number"
+ ? Math.round(item.progress)
+ : null;
+ return (
+ navigation.navigate("BookDetail", { ebookId: item.id })}
+ >
+ {item.cover_image ? (
+
+ ) : (
+
+
+ {item.title.charAt(0).toUpperCase()}
+
+
+ )}
+
+
+ {item.title}
+
+
+ {item.author || "Unknown author"}
+
+
+ {item.format?.toUpperCase()}
+ {progress !== null ? ` · ${progress}% read` : ""}
+
+
+
+ );
};
- const renderBook = ({ item }: { item: Book }) => (
-
- navigation.navigate("BookDetail", { bookId: item.id })
- }
- >
-
-
- {item.title.charAt(0).toUpperCase()}
-
-
-
-
- {item.title}
-
-
- {item.author}
-
- {item.total_pages} pages
-
-
- );
-
if (loading && books.length === 0) {
return (
@@ -88,9 +90,7 @@ export default function LibraryScreen({ navigation }: { navigation: any }): Reac
item.id}
- onEndReached={loadMore}
- onEndReachedThreshold={0.5}
+ keyExtractor={(item) => String(item.id)}
contentContainerStyle={styles.list}
refreshControl={
Your library is empty
- Add books to get started
+ Upload books from the web app to get started
}
@@ -125,6 +125,7 @@ const styles = StyleSheet.create({
},
list: {
padding: 16,
+ flexGrow: 1,
},
bookCard: {
flexDirection: "row",
@@ -164,7 +165,7 @@ const styles = StyleSheet.create({
color: "#888",
marginBottom: 4,
},
- bookPages: {
+ bookMeta: {
fontSize: 12,
color: "#666",
},
@@ -177,5 +178,6 @@ const styles = StyleSheet.create({
emptySubtext: {
fontSize: 14,
color: "#666",
+ textAlign: "center",
},
-});
\ No newline at end of file
+});
diff --git a/mobile/src/screens/LoginScreen.tsx b/mobile/src/screens/LoginScreen.tsx
index 766fafe..c4fd481 100644
--- a/mobile/src/screens/LoginScreen.tsx
+++ b/mobile/src/screens/LoginScreen.tsx
@@ -4,29 +4,31 @@ import {
Text,
TextInput,
TouchableOpacity,
- StyleSheet,
Alert,
ActivityIndicator,
KeyboardAvoidingView,
Platform,
} from "react-native";
import { useAuth } from "../context/AuthContext";
-import { isValidEmail } from "@cloud-reader/shared";
+import { authStyles } from "./authStyles";
+import { AuthFormError } from "./AuthFormError";
+import { requireValidEmail } from "./authValidation";
-export default function LoginScreen({ navigation }: { navigation: any }): ReactNode {
- const { state, login, clearError } = useAuth();
+export default function LoginScreen({
+ navigation,
+}: {
+ navigation: any;
+}): ReactNode {
+ const { login } = useAuth();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
+ const [error, setError] = useState(null);
+ const [submitting, setSubmitting] = useState(false);
const handleLogin = async () => {
- clearError();
+ setError(null);
- if (!email.trim()) {
- Alert.alert("Validation Error", "Please enter your email.");
- return;
- }
- if (!isValidEmail(email.trim())) {
- Alert.alert("Validation Error", "Please enter a valid email address.");
+ if (!requireValidEmail(email)) {
return;
}
if (!password) {
@@ -34,30 +36,29 @@ export default function LoginScreen({ navigation }: { navigation: any }): ReactN
return;
}
+ setSubmitting(true);
try {
await login(email.trim(), password);
} catch {
- // Error handled in context
+ setError("Invalid email or password.");
+ } finally {
+ setSubmitting(false);
}
};
return (
-
- Cloud Reader
- Sign in to your account
+
+ Cloud Reader
+ Sign in to your account
- {state.error && (
-
- {state.error}
-
- )}
+ {error ? : null}
- {state.isLoading ? (
+ {submitting ? (
) : (
- Sign In
+ Sign In
)}
navigation.navigate("Register")}>
-
+
Don't have an account?{" "}
- Sign Up
+ Sign Up
);
}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: "#0f0f23",
- },
- inner: {
- flex: 1,
- justifyContent: "center",
- paddingHorizontal: 24,
- },
- title: {
- fontSize: 32,
- fontWeight: "bold",
- color: "#fff",
- textAlign: "center",
- marginBottom: 8,
- },
- subtitle: {
- fontSize: 16,
- color: "#888",
- textAlign: "center",
- marginBottom: 32,
- },
- input: {
- backgroundColor: "#1a1a2e",
- borderRadius: 8,
- padding: 16,
- fontSize: 16,
- color: "#fff",
- marginBottom: 12,
- borderWidth: 1,
- borderColor: "#333",
- },
- button: {
- backgroundColor: "#4f8ef7",
- borderRadius: 8,
- padding: 16,
- alignItems: "center",
- marginTop: 8,
- marginBottom: 24,
- },
- buttonDisabled: {
- opacity: 0.6,
- },
- buttonText: {
- color: "#fff",
- fontSize: 16,
- fontWeight: "600",
- },
- errorBox: {
- backgroundColor: "rgba(255, 69, 58, 0.15)",
- borderRadius: 8,
- padding: 12,
- marginBottom: 16,
- borderWidth: 1,
- borderColor: "rgba(255, 69, 58, 0.3)",
- },
- errorText: {
- color: "#ff453a",
- fontSize: 14,
- textAlign: "center",
- },
- linkText: {
- color: "#888",
- textAlign: "center",
- fontSize: 14,
- },
- linkBold: {
- color: "#4f8ef7",
- fontWeight: "600",
- },
-});
\ No newline at end of file
diff --git a/mobile/src/screens/ReaderScreen.tsx b/mobile/src/screens/ReaderScreen.tsx
new file mode 100644
index 0000000..14d5544
--- /dev/null
+++ b/mobile/src/screens/ReaderScreen.tsx
@@ -0,0 +1,133 @@
+import { useEffect, useState, type ReactNode } from "react";
+import {
+ View,
+ Text,
+ TouchableOpacity,
+ ActivityIndicator,
+ StyleSheet,
+} from "react-native";
+import { SafeAreaView } from "react-native-safe-area-context";
+import type { RouteProp } from "@react-navigation/native";
+import type { EBookDetail } from "@cloud-reader/shared";
+import { ebooksApi } from "../api/ebooks";
+import { EpubReaderView } from "../components/reader/EpubReaderView";
+import type { AppStackParamList } from "../types";
+
+type ReaderRoute = RouteProp;
+
+export default function ReaderScreen({
+ route,
+ navigation,
+}: {
+ route: ReaderRoute;
+ navigation: any;
+}): ReactNode {
+ const { ebookId } = route.params;
+ const [book, setBook] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(false);
+
+ useEffect(() => {
+ let active = true;
+ ebooksApi
+ .get(ebookId)
+ .then(({ data }) => {
+ if (active) setBook(data);
+ })
+ .catch(() => {
+ if (active) setError(true);
+ })
+ .finally(() => {
+ if (active) setLoading(false);
+ });
+ return () => {
+ active = false;
+ };
+ }, [ebookId]);
+
+ if (loading) {
+ return (
+
+
+
+ );
+ }
+
+ if (error || !book) {
+ return (
+
+ Could not open this book.
+ navigation.goBack()}
+ >
+ Go back
+
+
+ );
+ }
+
+ const format = (book.format ?? "").toLowerCase();
+
+ if (format !== "epub") {
+ return (
+
+ PDF reading is coming soon
+
+ “{book.title}” is a {format.toUpperCase() || "non-EPUB"} file. PDF
+ reading isn't available on mobile yet — open it in the web reader
+ for now.
+
+ navigation.goBack()}
+ >
+ Go back
+
+
+ );
+ }
+
+ return (
+ navigation.goBack()}
+ />
+ );
+}
+
+const styles = StyleSheet.create({
+ centered: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ backgroundColor: "#0f0f23",
+ padding: 24,
+ },
+ placeholderTitle: {
+ fontSize: 20,
+ fontWeight: "700",
+ color: "#fff",
+ marginBottom: 12,
+ textAlign: "center",
+ },
+ message: {
+ fontSize: 15,
+ color: "#aaa",
+ textAlign: "center",
+ lineHeight: 22,
+ },
+ backButton: {
+ marginTop: 24,
+ backgroundColor: "#4f8ef7",
+ borderRadius: 10,
+ paddingHorizontal: 24,
+ paddingVertical: 12,
+ },
+ backText: {
+ color: "#fff",
+ fontSize: 15,
+ fontWeight: "600",
+ },
+});
diff --git a/mobile/src/screens/RegisterScreen.tsx b/mobile/src/screens/RegisterScreen.tsx
index e2cce09..3080b78 100644
--- a/mobile/src/screens/RegisterScreen.tsx
+++ b/mobile/src/screens/RegisterScreen.tsx
@@ -1,10 +1,8 @@
import { useState, type ReactNode } from "react";
import {
- View,
Text,
TextInput,
TouchableOpacity,
- StyleSheet,
Alert,
ActivityIndicator,
KeyboardAvoidingView,
@@ -12,40 +10,39 @@ import {
ScrollView,
} from "react-native";
import { useAuth } from "../context/AuthContext";
-import {
- isValidEmail,
- validatePasswordStrength,
-} from "@cloud-reader/shared";
+import { isStrongPassword } from "@cloud-reader/shared";
+import { authStyles } from "./authStyles";
+import { AuthFormError } from "./AuthFormError";
+import { requireValidEmail } from "./authValidation";
export default function RegisterScreen({
navigation,
}: {
navigation: any;
}): ReactNode {
- const { state, register, clearError } = useAuth();
+ const { register } = useAuth();
const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
+ const [error, setError] = useState(null);
+ const [submitting, setSubmitting] = useState(false);
const handleRegister = async () => {
- clearError();
+ setError(null);
if (!username.trim()) {
Alert.alert("Validation Error", "Please enter a username.");
return;
}
- if (!email.trim()) {
- Alert.alert("Validation Error", "Please enter your email.");
+ if (!requireValidEmail(email)) {
return;
}
- if (!isValidEmail(email.trim())) {
- Alert.alert("Validation Error", "Please enter a valid email address.");
- return;
- }
- const passwordError = validatePasswordStrength(password);
- if (passwordError) {
- Alert.alert("Validation Error", passwordError);
+ if (!isStrongPassword(password)) {
+ Alert.alert(
+ "Validation Error",
+ "Password must be at least 8 characters and include uppercase, lowercase, and a number.",
+ );
return;
}
if (password !== confirmPassword) {
@@ -53,30 +50,29 @@ export default function RegisterScreen({
return;
}
+ setSubmitting(true);
try {
- await register(email.trim(), password, username.trim());
+ await register(email.trim(), username.trim(), password);
} catch {
- // Error handled in context
+ setError("Could not create the account. Try a different email.");
+ } finally {
+ setSubmitting(false);
}
};
return (
-
- Create Account
- Join Cloud Reader
+
+ Create Account
+ Join Cloud Reader
- {state.error && (
-
- {state.error}
-
- )}
+ {error ? : null}
- {state.isLoading ? (
+ {submitting ? (
) : (
- Create Account
+ Create Account
)}
navigation.goBack()}>
-
+
Already have an account?{" "}
- Sign In
+ Sign In
);
}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: "#0f0f23",
- },
- inner: {
- flexGrow: 1,
- justifyContent: "center",
- paddingHorizontal: 24,
- paddingVertical: 48,
- },
- title: {
- fontSize: 28,
- fontWeight: "bold",
- color: "#fff",
- textAlign: "center",
- marginBottom: 8,
- },
- subtitle: {
- fontSize: 16,
- color: "#888",
- textAlign: "center",
- marginBottom: 32,
- },
- input: {
- backgroundColor: "#1a1a2e",
- borderRadius: 8,
- padding: 16,
- fontSize: 16,
- color: "#fff",
- marginBottom: 12,
- borderWidth: 1,
- borderColor: "#333",
- },
- button: {
- backgroundColor: "#4f8ef7",
- borderRadius: 8,
- padding: 16,
- alignItems: "center",
- marginTop: 8,
- marginBottom: 24,
- },
- buttonDisabled: {
- opacity: 0.6,
- },
- buttonText: {
- color: "#fff",
- fontSize: 16,
- fontWeight: "600",
- },
- errorBox: {
- backgroundColor: "rgba(255, 69, 58, 0.15)",
- borderRadius: 8,
- padding: 12,
- marginBottom: 16,
- borderWidth: 1,
- borderColor: "rgba(255, 69, 58, 0.3)",
- },
- errorText: {
- color: "#ff453a",
- fontSize: 14,
- textAlign: "center",
- },
- linkText: {
- color: "#888",
- textAlign: "center",
- fontSize: 14,
- },
- linkBold: {
- color: "#4f8ef7",
- fontWeight: "600",
- },
-});
\ No newline at end of file
diff --git a/mobile/src/screens/SettingsScreen.tsx b/mobile/src/screens/SettingsScreen.tsx
index 399b66d..62207e5 100644
--- a/mobile/src/screens/SettingsScreen.tsx
+++ b/mobile/src/screens/SettingsScreen.tsx
@@ -9,7 +9,7 @@ import {
import { useAuth } from "../context/AuthContext";
export default function SettingsScreen(): ReactNode {
- const { state, logout } = useAuth();
+ const { user, logout } = useAuth();
const handleLogout = () => {
Alert.alert("Logout", "Are you sure you want to sign out?", [
@@ -24,11 +24,11 @@ export default function SettingsScreen(): ReactNode {
Account
Username
- {state.user?.username ?? "—"}
+ {user?.username ?? "—"}
Email
- {state.user?.email ?? "—"}
+ {user?.email ?? "—"}
diff --git a/mobile/src/screens/authStyles.ts b/mobile/src/screens/authStyles.ts
new file mode 100644
index 0000000..6a61efb
--- /dev/null
+++ b/mobile/src/screens/authStyles.ts
@@ -0,0 +1,88 @@
+import { StyleSheet } from "react-native";
+
+/** Shared layout/styles for Login and Register screens. */
+export const authStyles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: "#0f0f23",
+ },
+ inner: {
+ flex: 1,
+ justifyContent: "center",
+ paddingHorizontal: 24,
+ },
+ innerScroll: {
+ flexGrow: 1,
+ justifyContent: "center",
+ paddingHorizontal: 24,
+ paddingVertical: 48,
+ },
+ title: {
+ fontSize: 32,
+ fontWeight: "bold",
+ color: "#fff",
+ textAlign: "center",
+ marginBottom: 8,
+ },
+ titleCompact: {
+ fontSize: 28,
+ fontWeight: "bold",
+ color: "#fff",
+ textAlign: "center",
+ marginBottom: 8,
+ },
+ subtitle: {
+ fontSize: 16,
+ color: "#888",
+ textAlign: "center",
+ marginBottom: 32,
+ },
+ input: {
+ backgroundColor: "#1a1a2e",
+ borderRadius: 8,
+ padding: 16,
+ fontSize: 16,
+ color: "#fff",
+ marginBottom: 12,
+ borderWidth: 1,
+ borderColor: "#333",
+ },
+ button: {
+ backgroundColor: "#4f8ef7",
+ borderRadius: 8,
+ padding: 16,
+ alignItems: "center",
+ marginTop: 8,
+ marginBottom: 24,
+ },
+ buttonDisabled: {
+ opacity: 0.6,
+ },
+ buttonText: {
+ color: "#fff",
+ fontSize: 16,
+ fontWeight: "600",
+ },
+ errorBox: {
+ backgroundColor: "rgba(255, 69, 58, 0.15)",
+ borderRadius: 8,
+ padding: 12,
+ marginBottom: 16,
+ borderWidth: 1,
+ borderColor: "rgba(255, 69, 58, 0.3)",
+ },
+ errorText: {
+ color: "#ff453a",
+ fontSize: 14,
+ textAlign: "center",
+ },
+ linkText: {
+ color: "#888",
+ textAlign: "center",
+ fontSize: 14,
+ },
+ linkBold: {
+ color: "#4f8ef7",
+ fontWeight: "600",
+ },
+});
diff --git a/mobile/src/screens/authValidation.ts b/mobile/src/screens/authValidation.ts
new file mode 100644
index 0000000..8c5bdff
--- /dev/null
+++ b/mobile/src/screens/authValidation.ts
@@ -0,0 +1,15 @@
+import { Alert } from "react-native";
+import { isValidEmail } from "@cloud-reader/shared";
+
+/** Returns true when email is non-empty and well-formed. */
+export function requireValidEmail(email: string): boolean {
+ if (!email.trim()) {
+ Alert.alert("Validation Error", "Please enter your email.");
+ return false;
+ }
+ if (!isValidEmail(email.trim())) {
+ Alert.alert("Validation Error", "Please enter a valid email address.");
+ return false;
+ }
+ return true;
+}
diff --git a/mobile/src/types/index.ts b/mobile/src/types/index.ts
index ee4da34..b040b11 100644
--- a/mobile/src/types/index.ts
+++ b/mobile/src/types/index.ts
@@ -1,8 +1,37 @@
// Mobile-specific type aliases and extensions not covered by shared types
-export type RootStackParamList = {
- Auth: undefined;
- Main: undefined;
- BookReader: { bookId: number };
- BookDetail: { bookId: number };
-};
\ No newline at end of file
+import type { NavigatorScreenParams } from "@react-navigation/native";
+import type { MainTabParamList } from "../navigation/MainNavigator";
+
+/** Stack hosted above the bottom tabs once the user is authenticated. */
+export type AppStackParamList = {
+ Tabs: NavigatorScreenParams | undefined;
+ BookDetail: { ebookId: number };
+ Reader: { ebookId: number };
+};
+
+/** EPUB bookmark/highlight, mirrors frontend/src/types Bookmark. */
+export interface Bookmark {
+ id: string;
+ ebook: number;
+ ebook_title: string;
+ epub_cfi: string;
+ chapter_index: number;
+ chapter_title: string;
+ page: number;
+ location_text: string;
+ content: string;
+ highlight_color?: string;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface CreateMarkerPayload {
+ ebook: number;
+ epub_cfi: string;
+ chapter_index: number;
+ chapter_title?: string;
+ location_text?: string;
+ content?: string;
+ highlight_color?: string;
+}
diff --git a/mobile/src/types/reader.ts b/mobile/src/types/reader.ts
new file mode 100644
index 0000000..2670a86
--- /dev/null
+++ b/mobile/src/types/reader.ts
@@ -0,0 +1,32 @@
+/**
+ * Reader module types for the mobile app. Mirrors
+ * frontend/src/types/reader.ts so settings and progress behave the same
+ * way across web and mobile.
+ */
+
+export interface ReadingSettings {
+ font_family: "sans-serif" | "serif" | "monospace";
+ font_size: number;
+ line_height: number;
+ margin_width: number;
+ background_color: string;
+ text_color: string;
+ brightness: number;
+ orientation_lock: "auto" | "portrait" | "landscape";
+ theme: "sepia" | "dark" | "light" | "paper";
+ created_at: string;
+ updated_at: string;
+}
+
+export type ThemePreset = ReadingSettings["theme"];
+export type FontFamily = ReadingSettings["font_family"];
+
+export interface ReadingProgress {
+ id: number;
+ book: number;
+ current_chapter: number;
+ current_position: number;
+ percentage: number;
+ epub_location: string;
+ updated_at: string;
+}
diff --git a/mobile/src/utils/epubTheme.ts b/mobile/src/utils/epubTheme.ts
new file mode 100644
index 0000000..d92dacf
--- /dev/null
+++ b/mobile/src/utils/epubTheme.ts
@@ -0,0 +1,66 @@
+import type { ReadingSettings, ThemePreset } from "../types/reader";
+
+/** CSS font stacks per family, mirrors frontend/src/utils/epubRendition.ts. */
+export const FONT_STACKS: Record = {
+ serif: 'Georgia, "Times New Roman", serif',
+ "sans-serif":
+ 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
+ monospace: 'ui-monospace, "Cascadia Code", monospace',
+};
+
+/** Background/text/chrome colors for each reader theme preset. */
+export const THEME_PALETTES: Record<
+ ThemePreset,
+ { background: string; text: string; chrome: string }
+> = {
+ light: { background: "#ffffff", text: "#1a1a1a", chrome: "#f2f2f2" },
+ dark: { background: "#121212", text: "#e0e0e0", chrome: "#1c1c1e" },
+ sepia: { background: "#f4ecd8", text: "#5b4636", chrome: "#e8ddc4" },
+ paper: { background: "#fbfbf8", text: "#2b2b2b", chrome: "#efefe9" },
+};
+
+export function resolvePalette(settings: ReadingSettings) {
+ const preset = THEME_PALETTES[settings.theme] ?? THEME_PALETTES.light;
+ return {
+ background: settings.background_color || preset.background,
+ text: settings.text_color || preset.text,
+ chrome: preset.chrome,
+ };
+}
+
+/**
+ * Build an epub.js theme object (selector -> CSS rules) from reader settings.
+ * Used with the epubjs-react-native `changeTheme` method.
+ */
+export function buildEpubTheme(
+ settings: ReadingSettings,
+): Record> {
+ const { background, text } = resolvePalette(settings);
+ const fontStack = FONT_STACKS[settings.font_family] ?? FONT_STACKS.serif;
+ const lineHeight = `${settings.line_height} !important`;
+ const fontFamily = `${fontStack} !important`;
+ const color = `${text} !important`;
+
+ return {
+ body: {
+ background: `${background} !important`,
+ color,
+ "font-family": fontFamily,
+ "line-height": lineHeight,
+ },
+ p: {
+ color,
+ "font-family": fontFamily,
+ "line-height": lineHeight,
+ },
+ li: { color, "font-family": fontFamily, "line-height": lineHeight },
+ span: { color },
+ a: { color },
+ h1: { color },
+ h2: { color },
+ h3: { color },
+ h4: { color },
+ h5: { color },
+ h6: { color },
+ };
+}
diff --git a/mobile/tsconfig.json b/mobile/tsconfig.json
index 52c6bb3..7d7ab21 100644
--- a/mobile/tsconfig.json
+++ b/mobile/tsconfig.json
@@ -12,7 +12,8 @@
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
- "@/*": ["src/*"]
+ "@/*": ["src/*"],
+ "@cloud-reader/shared": ["../packages/shared/src/index.ts"]
}
},
"include": ["**/*.ts", "**/*.tsx"],
diff --git a/yarn.lock b/yarn.lock
index 0ed8c5a..ab47131 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -57,7 +57,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz"
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
-"@babel/core@^7.0.0", "@babel/core@^7.0.0 || ^8.0.0-0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.1.0", "@babel/core@^7.11.0", "@babel/core@^7.11.1", "@babel/core@^7.11.6", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.13.16", "@babel/core@^7.16.0", "@babel/core@^7.20.0", "@babel/core@^7.25.2", "@babel/core@^7.28.0", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
+"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.16.0", "@babel/core@^7.20.0", "@babel/core@^7.25.2", "@babel/core@^7.28.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
version "7.29.7"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz"
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
@@ -370,6 +370,11 @@
"@babel/helper-create-class-features-plugin" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
+"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2":
+ version "7.21.0-placeholder-for-preset-env.2"
+ resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz"
+ integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
+
"@babel/plugin-proposal-private-property-in-object@^7.16.7":
version "7.21.11"
resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz"
@@ -380,11 +385,6 @@
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
-"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2":
- version "7.21.0-placeholder-for-preset-env.2"
- resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz"
- integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
-
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz"
@@ -434,7 +434,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.29.7"
-"@babel/plugin-syntax-flow@^7.12.1", "@babel/plugin-syntax-flow@^7.14.5", "@babel/plugin-syntax-flow@^7.29.7":
+"@babel/plugin-syntax-flow@^7.12.1", "@babel/plugin-syntax-flow@^7.29.7":
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==
@@ -898,7 +898,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.29.7"
-"@babel/plugin-transform-react-jsx@^7.14.9", "@babel/plugin-transform-react-jsx@^7.25.2", "@babel/plugin-transform-react-jsx@^7.29.7":
+"@babel/plugin-transform-react-jsx@^7.25.2", "@babel/plugin-transform-react-jsx@^7.29.7":
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==
@@ -1029,7 +1029,7 @@
"@babel/helper-create-regexp-features-plugin" "^7.29.7"
"@babel/helper-plugin-utils" "^7.29.7"
-"@babel/preset-env@^7.1.6", "@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4":
+"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4":
version "7.29.7"
resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz"
integrity sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==
@@ -1211,46 +1211,6 @@
resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@cloud-reader/frontend@file:C:\\Users\\Cristhian\\Projects\\codes\\cloud-reader\\frontend":
- version "1.0.0"
- resolved "file:frontend"
- dependencies:
- axios "^1.7.9"
- dompurify "^3.4.7"
- pdfjs-dist "^4.10.38"
- react "^19.0.0"
- react-dom "^19.0.0"
- react-i18n-lite "^1.0.10"
- react-reader "^2.0.15"
- react-router-dom "^7.1.0"
-
-"@cloud-reader/mobile@file:C:\\Users\\Cristhian\\Projects\\codes\\cloud-reader\\mobile":
- version "1.0.0"
- resolved "file:mobile"
- dependencies:
- "@cloud-reader/shared" "*"
- "@react-native-async-storage/async-storage" "2.1.0"
- "@react-navigation/bottom-tabs" "^7.0.0"
- "@react-navigation/native" "^7.0.0"
- "@react-navigation/native-stack" "^7.0.0"
- axios "^1.7.9"
- expo "~52.0.0"
- expo-document-picker "~13.0.0"
- expo-file-system "~18.0.0"
- expo-status-bar "~2.0.0"
- react "^19.0.0"
- react-native "0.76.6"
- react-native-gesture-handler "~2.20.0"
- react-native-reanimated "~3.16.0"
- react-native-safe-area-context "4.14.1"
- react-native-screens "~4.4.0"
-
-"@cloud-reader/shared@*", "@cloud-reader/shared@file:C:\\Users\\Cristhian\\Projects\\codes\\cloud-reader\\packages\\shared":
- version "1.0.0"
- resolved "file:packages/shared"
- dependencies:
- typescript "~5.7.0"
-
"@csstools/color-helpers@^5.1.0":
version "5.1.0"
resolved "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz"
@@ -1269,12 +1229,12 @@
"@csstools/color-helpers" "^5.1.0"
"@csstools/css-calc" "^2.1.4"
-"@csstools/css-parser-algorithms@^3.0.4", "@csstools/css-parser-algorithms@^3.0.5":
+"@csstools/css-parser-algorithms@^3.0.4":
version "3.0.5"
resolved "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz"
integrity sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==
-"@csstools/css-tokenizer@^3.0.3", "@csstools/css-tokenizer@^3.0.4":
+"@csstools/css-tokenizer@^3.0.3":
version "3.0.4"
resolved "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz"
integrity sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==
@@ -1397,6 +1357,251 @@
dependencies:
"@types/hammerjs" "^2.0.36"
+"@epubjs-react-native/core@1.4.7":
+ version "1.4.7"
+ resolved "https://registry.yarnpkg.com/@epubjs-react-native/core/-/core-1.4.7.tgz#0c19a07a26dc9941805fbe78c6201e7af7c1a70b"
+ integrity sha512-bDzL0DU13IyfRZRydz36bh7HqDyUV3VKIFYOAYPBejMUAK4LYZclUb+NdgiwyynhhkUZQNdaWgSdtAGzGmsxEw==
+
+"@epubjs-react-native/expo-file-system@1.1.4":
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/@epubjs-react-native/expo-file-system/-/expo-file-system-1.1.4.tgz#8699e19053b8e7ed458970177bffc72bce65e276"
+ integrity sha512-/Ked2Zg9UART5ZYMI1KAVdUOd8mK9xVFD6d7rATfGhzIGbReX4WrR03oG5LdcdCMHHZbDis0ztRnUX9VSScZvw==
+
+"@esbuild/aix-ppc64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f"
+ integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
+
+"@esbuild/aix-ppc64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c"
+ integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==
+
+"@esbuild/android-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052"
+ integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
+
+"@esbuild/android-arm64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752"
+ integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==
+
+"@esbuild/android-arm@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28"
+ integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
+
+"@esbuild/android-arm@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a"
+ integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==
+
+"@esbuild/android-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e"
+ integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
+
+"@esbuild/android-x64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16"
+ integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==
+
+"@esbuild/darwin-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a"
+ integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
+
+"@esbuild/darwin-arm64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd"
+ integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==
+
+"@esbuild/darwin-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22"
+ integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
+
+"@esbuild/darwin-x64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e"
+ integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==
+
+"@esbuild/freebsd-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e"
+ integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
+
+"@esbuild/freebsd-arm64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe"
+ integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==
+
+"@esbuild/freebsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261"
+ integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
+
+"@esbuild/freebsd-x64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3"
+ integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==
+
+"@esbuild/linux-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b"
+ integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
+
+"@esbuild/linux-arm64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977"
+ integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==
+
+"@esbuild/linux-arm@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9"
+ integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
+
+"@esbuild/linux-arm@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9"
+ integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==
+
+"@esbuild/linux-ia32@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2"
+ integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
+
+"@esbuild/linux-ia32@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0"
+ integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==
+
+"@esbuild/linux-loong64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df"
+ integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
+
+"@esbuild/linux-loong64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0"
+ integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==
+
+"@esbuild/linux-mips64el@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe"
+ integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
+
+"@esbuild/linux-mips64el@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd"
+ integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==
+
+"@esbuild/linux-ppc64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4"
+ integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
+
+"@esbuild/linux-ppc64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869"
+ integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==
+
+"@esbuild/linux-riscv64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc"
+ integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
+
+"@esbuild/linux-riscv64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6"
+ integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==
+
+"@esbuild/linux-s390x@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de"
+ integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
+
+"@esbuild/linux-s390x@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663"
+ integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==
+
+"@esbuild/linux-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0"
+ integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
+
+"@esbuild/linux-x64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz#0583775685ca82066d04c3507f09524d3cd7a306"
+ integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==
+
+"@esbuild/netbsd-arm64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4"
+ integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==
+
+"@esbuild/netbsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047"
+ integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
+
+"@esbuild/netbsd-x64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076"
+ integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==
+
+"@esbuild/openbsd-arm64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd"
+ integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==
+
+"@esbuild/openbsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70"
+ integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
+
+"@esbuild/openbsd-x64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679"
+ integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==
+
+"@esbuild/openharmony-arm64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d"
+ integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==
+
+"@esbuild/sunos-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b"
+ integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
+
+"@esbuild/sunos-x64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6"
+ integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==
+
+"@esbuild/win32-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d"
+ integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
+
+"@esbuild/win32-arm64@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323"
+ integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==
+
+"@esbuild/win32-ia32@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b"
+ integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
+
+"@esbuild/win32-ia32@0.25.12":
+ version "0.25.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267"
+ integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==
+
"@esbuild/win32-x64@0.21.5":
version "0.21.5"
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz"
@@ -1651,7 +1856,7 @@
json5 "^2.2.3"
write-file-atomic "^2.3.0"
-"@expo/metro-config@~0.19.12", "@expo/metro-config@0.19.12":
+"@expo/metro-config@0.19.12", "@expo/metro-config@~0.19.12":
version "0.19.12"
resolved "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.19.12.tgz"
integrity sha512-fhT3x1ikQWHpZgw7VrEghBdscFPz1laRYa8WcVRB18nTTqorF6S8qPYslkJu1faEziHZS7c2uyDzTYnrg/CKbg==
@@ -2149,6 +2354,56 @@
resolved "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz"
integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==
+"@napi-rs/canvas-android-arm64@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz#b7c68b91d57702a5fc523fa82de72ea741e6766e"
+ integrity sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==
+
+"@napi-rs/canvas-darwin-arm64@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz#d1686fa6ca699b07640efa5f45425db0a4e725e2"
+ integrity sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==
+
+"@napi-rs/canvas-darwin-x64@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz#92978fd7eca21f7f1b59bd13ba3ce7c0e7c879a1"
+ integrity sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==
+
+"@napi-rs/canvas-linux-arm-gnueabihf@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz#95f9892e1d5a8274871d8ee406374e9ef692bd9f"
+ integrity sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==
+
+"@napi-rs/canvas-linux-arm64-gnu@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz#6b2b7c4bb016b8f5308115ac9ae909df4967a94b"
+ integrity sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==
+
+"@napi-rs/canvas-linux-arm64-musl@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz#48cf6342543e4f87cf1f8e9b1aaa19ad85bcc178"
+ integrity sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==
+
+"@napi-rs/canvas-linux-riscv64-gnu@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz#71b011007b03755c834a961735302c5837b041da"
+ integrity sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==
+
+"@napi-rs/canvas-linux-x64-gnu@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz#3f479d3b8b8c4658e5dec1b943ad7d2eefd2811f"
+ integrity sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==
+
+"@napi-rs/canvas-linux-x64-musl@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz#1beaca22c1fe97709a9c287115cb3c90194ddec6"
+ integrity sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==
+
+"@napi-rs/canvas-win32-arm64-msvc@0.1.100":
+ version "0.1.100"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz#8a1728b455dd17965f95c0bfdf6753be8c5851c0"
+ integrity sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==
+
"@napi-rs/canvas-win32-x64-msvc@0.1.100":
version "0.1.100"
resolved "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz"
@@ -2186,7 +2441,7 @@
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
-"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
@@ -2522,7 +2777,7 @@
sf-symbols-typescript "^2.1.0"
warn-once "^0.1.1"
-"@react-navigation/native@^7.0.0", "@react-navigation/native@^7.2.5":
+"@react-navigation/native@^7.0.0":
version "7.2.5"
resolved "https://registry.npmjs.org/@react-navigation/native/-/native-7.2.5.tgz"
integrity sha512-01AAUQiiHQAfTabq+ZyU1/ZWq+AbB/J3v0CB0UTJSON6M6cuadWNsbChzrZUdqQvHrXvg96U5i2PQLJzK3+zpg==
@@ -2582,6 +2837,121 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
+"@rollup/rollup-android-arm-eabi@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz#3a04f01e9f01392bbef5920b94aa3b88794be7ab"
+ integrity sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==
+
+"@rollup/rollup-android-arm64@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz#e371b653ceabc900790ae73f5548a0fd7cd63a70"
+ integrity sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==
+
+"@rollup/rollup-darwin-arm64@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz#2a5aa70432e39816d666d79287a7324cfc3b4e72"
+ integrity sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==
+
+"@rollup/rollup-darwin-x64@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz#c3b5b49629379cd9cdc5d841bf00ed44ebf393dd"
+ integrity sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==
+
+"@rollup/rollup-freebsd-arm64@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz#f929d8e0462fae6602fc960beeabd7287d859283"
+ integrity sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==
+
+"@rollup/rollup-freebsd-x64@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz#c01cb58031226f95d0900b1ec847f4fb32c6e809"
+ integrity sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz#f29d890c4858c8e0d3be01677eef4f6a359eed9d"
+ integrity sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==
+
+"@rollup/rollup-linux-arm-musleabihf@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz#1ebfc8eb9f66136ed2faae5f44995add5ca3c964"
+ integrity sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==
+
+"@rollup/rollup-linux-arm64-gnu@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz#c1fa823c2c4ce46ba7f61de1a4c3fdadd4fb4e7b"
+ integrity sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==
+
+"@rollup/rollup-linux-arm64-musl@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz#a7f18854d0471b78bda8ea38f0891a4e059b571d"
+ integrity sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==
+
+"@rollup/rollup-linux-loong64-gnu@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz#83658a9a4576bcce8cef85b2c78b9b649d2200c4"
+ integrity sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==
+
+"@rollup/rollup-linux-loong64-musl@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz#fd2af677ae3417bb58d57ae37dd0d84686e40244"
+ integrity sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==
+
+"@rollup/rollup-linux-ppc64-gnu@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz#6481647181c4cf8f1ddbd99f62c84cfc56c1a94a"
+ integrity sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==
+
+"@rollup/rollup-linux-ppc64-musl@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz#18610a1a1550e28a5042ca916f898419540f17f4"
+ integrity sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==
+
+"@rollup/rollup-linux-riscv64-gnu@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz#597bb80465a2621dbe0de0a41c66394a8a7e9a6e"
+ integrity sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==
+
+"@rollup/rollup-linux-riscv64-musl@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz#a2a919a9f927ef7f24a60af77e3cb55f1ad59e4d"
+ integrity sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==
+
+"@rollup/rollup-linux-s390x-gnu@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz#3166f6ceae7df9bbfddf9f36be1937231e13e3c6"
+ integrity sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==
+
+"@rollup/rollup-linux-x64-gnu@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz#23c9bf79771d804fb87415eb0767569f273261e5"
+ integrity sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==
+
+"@rollup/rollup-linux-x64-musl@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz#97941c6b94d67fe25cde0f027c10a19f2d1fdd39"
+ integrity sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==
+
+"@rollup/rollup-openbsd-x64@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz#7aeb7d92e2cd1d399f56daf75c39040b777b6c77"
+ integrity sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==
+
+"@rollup/rollup-openharmony-arm64@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz#925de61ae83bf99aa636e8acea87432e8c0ffaab"
+ integrity sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==
+
+"@rollup/rollup-win32-arm64-msvc@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz#888ab83842721491044c46a7407e1f38f3235bb4"
+ integrity sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==
+
+"@rollup/rollup-win32-ia32-msvc@4.60.4":
+ version "4.60.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz#fa30ac24e3f0232139d2a47500560a28695764d4"
+ integrity sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==
+
"@rollup/rollup-win32-x64-gnu@4.60.4":
version "4.60.4"
resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz"
@@ -2785,7 +3155,7 @@
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
-"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.9", "@types/babel__core@^7.20.5":
+"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.20.5":
version "7.20.5"
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
@@ -2987,7 +3357,7 @@
dependencies:
"@types/node" "*"
-"@types/node@*", "@types/node@^18.0.0 || ^20.0.0 || >=22.0.0", "@types/node@^18.0.0 || >=20.0.0":
+"@types/node@*":
version "25.9.1"
resolved "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz"
integrity sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==
@@ -3019,12 +3389,12 @@
resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz"
integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
-"@types/react-dom@^18.0.0 || ^19.0.0", "@types/react-dom@^19.0.0":
+"@types/react-dom@^19.0.0":
version "19.2.3"
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz"
integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==
-"@types/react@^18.0.0 || ^19.0.0", "@types/react@^18.2.6", "@types/react@^19.0.0", "@types/react@^19.2.0":
+"@types/react@^19.0.0":
version "19.2.15"
resolved "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz"
integrity sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==
@@ -3106,7 +3476,7 @@
resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz"
integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
-"@types/trusted-types@^2.0.2", "@types/trusted-types@^2.0.7":
+"@types/trusted-types@^2.0.2":
version "2.0.7"
resolved "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz"
integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==
@@ -3137,7 +3507,7 @@
dependencies:
"@types/yargs-parser" "*"
-"@typescript-eslint/eslint-plugin@^4.0.0 || ^5.0.0", "@typescript-eslint/eslint-plugin@^5.5.0":
+"@typescript-eslint/eslint-plugin@^5.5.0":
version "5.62.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz"
integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==
@@ -3160,7 +3530,7 @@
dependencies:
"@typescript-eslint/utils" "5.62.0"
-"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.5.0":
+"@typescript-eslint/parser@^5.5.0":
version "5.62.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz"
integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==
@@ -3206,7 +3576,7 @@
semver "^7.3.7"
tsutils "^3.21.0"
-"@typescript-eslint/utils@^5.58.0", "@typescript-eslint/utils@5.62.0":
+"@typescript-eslint/utils@5.62.0", "@typescript-eslint/utils@^5.58.0":
version "5.62.0"
resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz"
integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==
@@ -3280,7 +3650,7 @@
estree-walker "^3.0.3"
magic-string "^0.30.12"
-"@vitest/pretty-format@^2.1.9", "@vitest/pretty-format@2.1.9":
+"@vitest/pretty-format@2.1.9", "@vitest/pretty-format@^2.1.9":
version "2.1.9"
resolved "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz"
integrity sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==
@@ -3320,7 +3690,7 @@
loupe "^3.1.2"
tinyrainbow "^1.2.0"
-"@webassemblyjs/ast@^1.14.1", "@webassemblyjs/ast@1.14.1":
+"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1":
version "1.14.1"
resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz"
integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==
@@ -3421,7 +3791,7 @@
"@webassemblyjs/wasm-gen" "1.14.1"
"@webassemblyjs/wasm-parser" "1.14.1"
-"@webassemblyjs/wasm-parser@^1.14.1", "@webassemblyjs/wasm-parser@1.14.1":
+"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1":
version "1.14.1"
resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz"
integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==
@@ -3504,16 +3874,16 @@ acorn-walk@^7.1.1:
resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
-"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.14.0, acorn@^8.15.0, acorn@^8.16.0, acorn@^8.2.4, acorn@^8.9.0:
- version "8.16.0"
- resolved "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz"
- integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==
-
acorn@^7.1.1:
version "7.4.1"
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
+acorn@^8.15.0, acorn@^8.16.0, acorn@^8.2.4, acorn@^8.9.0:
+ version "8.16.0"
+ resolved "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz"
+ integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==
+
address@^1.0.1, address@^1.1.2:
version "1.2.2"
resolved "https://registry.npmjs.org/address/-/address-1.2.2.tgz"
@@ -3527,16 +3897,6 @@ adjust-sourcemap-loader@^4.0.0:
loader-utils "^2.0.0"
regex-parser "^2.2.11"
-agent-base@^7.1.0:
- version "7.1.4"
- resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz"
- integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==
-
-agent-base@^7.1.2:
- version "7.1.4"
- resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz"
- integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==
-
agent-base@6:
version "6.0.2"
resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
@@ -3544,6 +3904,11 @@ agent-base@6:
dependencies:
debug "4"
+agent-base@^7.1.0, agent-base@^7.1.2:
+ version "7.1.4"
+ resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz"
+ integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==
+
aggregate-error@^3.0.0:
version "3.1.0"
resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz"
@@ -3571,7 +3936,7 @@ ajv-keywords@^5.1.0:
dependencies:
fast-deep-equal "^3.1.3"
-ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.9.1:
+ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5:
version "6.15.0"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz"
integrity sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==
@@ -3581,17 +3946,7 @@ ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.9.1:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
-ajv@^8.0.0, ajv@^8.8.2, ajv@^8.9.0:
- version "8.20.0"
- resolved "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz"
- integrity sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==
- dependencies:
- fast-deep-equal "^3.1.3"
- fast-uri "^3.0.1"
- json-schema-traverse "^1.0.0"
- require-from-string "^2.0.2"
-
-ajv@^8.6.0, ajv@>=8:
+ajv@^8.0.0, ajv@^8.6.0, ajv@^8.9.0:
version "8.20.0"
resolved "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz"
integrity sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==
@@ -4225,13 +4580,6 @@ bplist-creator@0.1.0:
dependencies:
stream-buffers "2.2.x"
-bplist-parser@^0.3.1:
- 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==
- dependencies:
- big-integer "1.6.x"
-
bplist-parser@0.3.1:
version "0.3.1"
resolved "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz"
@@ -4239,6 +4587,13 @@ bplist-parser@0.3.1:
dependencies:
big-integer "1.6.x"
+bplist-parser@^0.3.1:
+ 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==
+ dependencies:
+ big-integer "1.6.x"
+
brace-expansion@^1.1.7:
version "1.1.15"
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz"
@@ -4266,7 +4621,7 @@ browser-process-hrtime@^1.0.0:
resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz"
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
-browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.21.4, browserslist@^4.24.0, browserslist@^4.28.1, browserslist@^4.28.2, "browserslist@>= 4", "browserslist@>= 4.21.0", browserslist@>=4:
+browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.21.4, browserslist@^4.24.0, browserslist@^4.28.1, browserslist@^4.28.2:
version "4.28.2"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz"
integrity sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==
@@ -4320,7 +4675,7 @@ builtin-modules@^3.1.0:
resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz"
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
-bytes@~3.1.2, bytes@3.1.2:
+bytes@3.1.2, bytes@~3.1.2:
version "3.1.2"
resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
@@ -4452,25 +4807,7 @@ chai@^5.1.2:
loupe "^3.1.0"
pathval "^2.0.0"
-chalk@^2.0.1:
- version "2.4.2"
- resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
- integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
-
-chalk@^2.4.1:
- version "2.4.2"
- resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
- integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
-
-chalk@^2.4.2:
+chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -4663,16 +5000,16 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
-color-name@^1.0.0, color-name@~1.1.4:
- version "1.1.4"
- resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
- integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+color-name@^1.0.0, color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
color-string@^1.9.0:
version "1.9.1"
resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz"
@@ -4995,14 +5332,6 @@ css-select@^4.1.3:
domutils "^2.8.0"
nth-check "^2.0.1"
-css-tree@^1.1.2, css-tree@^1.1.3:
- version "1.1.3"
- resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz"
- integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
- dependencies:
- mdn-data "2.0.14"
- source-map "^0.6.1"
-
css-tree@1.0.0-alpha.37:
version "1.0.0-alpha.37"
resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz"
@@ -5011,6 +5340,14 @@ css-tree@1.0.0-alpha.37:
mdn-data "2.0.4"
source-map "^0.6.1"
+css-tree@^1.1.2, css-tree@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz"
+ integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
+ dependencies:
+ mdn-data "2.0.14"
+ source-map "^0.6.1"
+
css-what@^3.2.1:
version "3.4.2"
resolved "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz"
@@ -5122,7 +5459,7 @@ csstype@^3.0.2, csstype@^3.2.2:
resolved "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz"
integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
-d@^1.0.1, d@^1.0.2, d@1:
+d@1, d@^1.0.1, d@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/d/-/d-1.0.2.tgz"
integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==
@@ -5179,54 +5516,26 @@ data-view-byte-offset@^1.0.1:
es-errors "^1.3.0"
is-data-view "^1.0.1"
-debug@^2.2.0:
+debug@2.6.9, debug@^2.2.0, debug@^2.6.0, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
-debug@^2.6.0:
- version "2.6.9"
- resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
- integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
- dependencies:
- ms "2.0.0"
-
-debug@^2.6.9:
- version "2.6.9"
- resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
- integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
- dependencies:
- ms "2.0.0"
-
-debug@^3.1.0:
- version "3.2.7"
- resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
- integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
- dependencies:
- ms "^2.1.1"
-
-debug@^3.2.7:
- version "3.2.7"
- resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
- integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
- dependencies:
- ms "^2.1.1"
-
-debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7, debug@^4.4.3, debug@4:
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7, debug@^4.4.3:
version "4.4.3"
resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
dependencies:
ms "^2.1.3"
-debug@2.6.9:
- version "2.6.9"
- resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
- integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+debug@^3.1.0, debug@^3.2.7:
+ version "3.2.7"
+ resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
- ms "2.0.0"
+ ms "^2.1.1"
decimal.js@^10.2.1, decimal.js@^10.4.3:
version "10.6.0"
@@ -5327,17 +5636,17 @@ delayed-stream@~1.0.0:
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+depd@2.0.0, depd@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz"
integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
-depd@~2.0.0, depd@2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
- integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
-
-destroy@~1.2.0, destroy@1.2.0:
+destroy@1.2.0, destroy@~1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
@@ -5420,6 +5729,14 @@ dom-converter@^0.2.0:
dependencies:
utila "~0.4"
+dom-serializer@0:
+ version "0.2.2"
+ resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz"
+ integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==
+ dependencies:
+ domelementtype "^2.0.1"
+ entities "^2.0.0"
+
dom-serializer@^1.0.1:
version "1.4.1"
resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz"
@@ -5429,24 +5746,16 @@ dom-serializer@^1.0.1:
domhandler "^4.2.0"
entities "^2.0.0"
-dom-serializer@0:
- version "0.2.2"
- resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz"
- integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==
- dependencies:
- domelementtype "^2.0.1"
- entities "^2.0.0"
+domelementtype@1:
+ version "1.3.1"
+ resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz"
+ integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
domelementtype@^2.0.1, domelementtype@^2.2.0:
version "2.3.0"
resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
-domelementtype@1:
- version "1.3.1"
- resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz"
- integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
-
domexception@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz"
@@ -5461,13 +5770,6 @@ domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
dependencies:
domelementtype "^2.2.0"
-dompurify@^3.4.7:
- version "3.4.7"
- resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz"
- integrity sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==
- optionalDependencies:
- "@types/trusted-types" "^2.0.7"
-
domutils@^1.7.0:
version "1.7.0"
resolved "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz"
@@ -6047,7 +6349,7 @@ eslint-plugin-testing-library@^5.0.1:
dependencies:
"@typescript-eslint/utils" "^5.58.0"
-eslint-scope@^5.1.1, eslint-scope@5.1.1:
+eslint-scope@5.1.1, eslint-scope@^5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
@@ -6084,7 +6386,7 @@ eslint-webpack-plugin@^3.1.1:
normalize-path "^3.0.0"
schema-utils "^4.0.0"
-eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", "eslint@^7.5.0 || ^8.0.0", "eslint@^7.5.0 || ^8.0.0 || ^9.0.0", eslint@^8.0.0, eslint@^8.1.0, eslint@^8.3.0, "eslint@>= 6":
+eslint@^8.3.0:
version "8.57.1"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
@@ -6147,16 +6449,16 @@ espree@^9.6.0, espree@^9.6.1:
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.4.1"
-esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0:
- version "4.0.1"
- resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
- integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-
esprima@1.2.5:
version "1.2.5"
resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
integrity sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==
+esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
esquery@^1.4.2:
version "1.7.0"
resolved "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz"
@@ -6292,11 +6594,6 @@ expo-constants@~17.0.8:
"@expo/config" "~10.0.11"
"@expo/env" "~0.4.2"
-expo-document-picker@~13.0.0:
- version "13.0.3"
- resolved "https://registry.npmjs.org/expo-document-picker/-/expo-document-picker-13.0.3.tgz"
- integrity sha512-348xcsiA/YhgWm1SuJNNdb5cUDpRJYCyIk8MhOU2MEDxbVRR+Q1TiUBTCIMVqaWHcxsFQzP56Wwv9n24qjeILg==
-
expo-file-system@~18.0.0, expo-file-system@~18.0.12:
version "18.0.12"
resolved "https://registry.npmjs.org/expo-file-system/-/expo-file-system-18.0.12.tgz"
@@ -6342,7 +6639,7 @@ expo-status-bar@~2.0.0:
resolved "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-2.0.1.tgz"
integrity sha512-AkIPX7jWHRPp83UBZ1iXtVvyr0g+DgBVvIXTtlmPtmUsm8Vq9Bb5IGj86PW8osuFlgoTVAg7HI/+Ok7yEYwiRg==
-expo@*, expo@~52.0.0:
+expo@~52.0.0:
version "52.0.49"
resolved "https://registry.npmjs.org/expo/-/expo-52.0.49.tgz"
integrity sha512-ge3gUnuyGEePWWKzPY7TQ7FsvtFTdmsdYDHeBVUjMr9KIoQig/gf8A03oH26p3UtTL6sUJcyOIg9vwIHGNPSUw==
@@ -6492,12 +6789,7 @@ fbjs@^3.0.0:
setimmediate "^1.0.5"
ua-parser-js "^1.0.35"
-fdir@^6.4.4:
- version "6.5.0"
- resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz"
- integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
-
-fdir@^6.5.0:
+fdir@^6.4.4, fdir@^6.5.0:
version "6.5.0"
resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz"
integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
@@ -6546,19 +6838,6 @@ filter-obj@^1.1.0:
resolved "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz"
integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==
-finalhandler@~1.3.1:
- version "1.3.2"
- resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz"
- integrity sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==
- dependencies:
- debug "2.6.9"
- encodeurl "~2.0.0"
- escape-html "~1.0.3"
- on-finished "~2.4.1"
- parseurl "~1.3.3"
- statuses "~2.0.2"
- unpipe "~1.0.0"
-
finalhandler@1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz"
@@ -6572,6 +6851,19 @@ finalhandler@1.1.2:
statuses "~1.5.0"
unpipe "~1.0.0"
+finalhandler@~1.3.1:
+ version "1.3.2"
+ resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz"
+ integrity sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ on-finished "~2.4.1"
+ parseurl "~1.3.3"
+ statuses "~2.0.2"
+ unpipe "~1.0.0"
+
find-cache-dir@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz"
@@ -6597,15 +6889,7 @@ find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
-find-up@^4.0.0:
- version "4.1.0"
- resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
- integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
- dependencies:
- locate-path "^5.0.0"
- path-exists "^4.0.0"
-
-find-up@^4.1.0:
+find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
@@ -6700,18 +6984,7 @@ form-data@^3.0.0, form-data@^3.0.1:
hasown "^2.0.2"
mime-types "^2.1.35"
-form-data@^4.0.0:
- version "4.0.5"
- resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz"
- integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==
- dependencies:
- asynckit "^0.4.0"
- combined-stream "^1.0.8"
- es-set-tostringtag "^2.1.0"
- hasown "^2.0.2"
- mime-types "^2.1.12"
-
-form-data@^4.0.5:
+form-data@^4.0.0, form-data@^4.0.5:
version "4.0.5"
resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz"
integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==
@@ -6742,6 +7015,16 @@ fresh@~0.5.2:
resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz"
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+fs-extra@9.0.0:
+ version "9.0.0"
+ resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz"
+ integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==
+ dependencies:
+ at-least-node "^1.0.0"
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^1.0.0"
+
fs-extra@^10.0.0:
version "10.1.0"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz"
@@ -6770,16 +7053,6 @@ fs-extra@~8.1.0:
jsonfile "^4.0.0"
universalify "^0.1.0"
-fs-extra@9.0.0:
- version "9.0.0"
- resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz"
- integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==
- dependencies:
- at-least-node "^1.0.0"
- graceful-fs "^4.2.0"
- jsonfile "^6.0.1"
- universalify "^1.0.0"
-
fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz"
@@ -6804,6 +7077,11 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
@@ -6920,31 +7198,7 @@ glob-to-regexp@^0.4.1:
resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
-glob@^10.2.2:
- version "10.5.0"
- resolved "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz"
- integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==
- 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"
-
-glob@^10.3.10:
- version "10.5.0"
- resolved "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz"
- integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==
- 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"
-
-glob@^10.4.2:
+glob@^10.2.2, glob@^10.3.10, glob@^10.4.2:
version "10.5.0"
resolved "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz"
integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==
@@ -7297,21 +7551,14 @@ human-signals@^2.1.0:
resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
-iconv-lite@^0.6.3:
- version "0.6.3"
- resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
- integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
- dependencies:
- safer-buffer ">= 2.1.2 < 3.0.0"
-
-iconv-lite@~0.4.24, iconv-lite@0.4.24:
+iconv-lite@0.4.24, iconv-lite@~0.4.24:
version "0.4.24"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
-iconv-lite@0.6.3:
+iconv-lite@0.6.3, iconv-lite@^0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
@@ -7404,7 +7651,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3, inherits@~2.0.4, inherits@2, inherits@2.0.4:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3, inherits@~2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -7431,7 +7678,7 @@ internal-slot@^1.1.0:
hasown "^2.0.2"
side-channel "^1.1.0"
-invariant@^2.2.4:
+invariant@2.2.4, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@@ -7443,7 +7690,7 @@ ip-regex@^2.1.0:
resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz"
integrity sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==
-ipaddr.js@^1.9.0, ipaddr.js@1.9.1:
+ipaddr.js@1.9.1, ipaddr.js@^1.9.0:
version "1.9.1"
resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz"
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
@@ -8172,7 +8419,7 @@ jest-resolve-dependencies@^27.5.1:
jest-regex-util "^27.5.1"
jest-snapshot "^27.5.1"
-jest-resolve@*, jest-resolve@^27.4.2, jest-resolve@^27.5.1:
+jest-resolve@^27.4.2, jest-resolve@^27.5.1:
version "27.5.1"
resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz"
integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==
@@ -8416,7 +8663,7 @@ jest-worker@^29.7.0:
merge-stream "^2.0.0"
supports-color "^8.0.0"
-"jest@^27.0.0 || ^28.0.0", jest@^27.4.3:
+jest@^27.4.3:
version "27.5.1"
resolved "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz"
integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==
@@ -8430,7 +8677,7 @@ jimp-compact@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==
-jiti@^1.21.7, jiti@>=1.21.0:
+jiti@^1.21.7:
version "1.21.7"
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz"
integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==
@@ -8495,33 +8742,6 @@ jscodeshift@^0.14.0:
temp "^0.8.4"
write-file-atomic "^2.3.0"
-jsdom@*, jsdom@^25.0.0:
- version "25.0.1"
- resolved "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz"
- integrity sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==
- dependencies:
- cssstyle "^4.1.0"
- data-urls "^5.0.0"
- decimal.js "^10.4.3"
- form-data "^4.0.0"
- html-encoding-sniffer "^4.0.0"
- http-proxy-agent "^7.0.2"
- https-proxy-agent "^7.0.5"
- is-potential-custom-element-name "^1.0.1"
- nwsapi "^2.2.12"
- parse5 "^7.1.2"
- rrweb-cssom "^0.7.1"
- saxes "^6.0.0"
- symbol-tree "^3.2.4"
- tough-cookie "^5.0.0"
- w3c-xmlserializer "^5.0.0"
- webidl-conversions "^7.0.0"
- whatwg-encoding "^3.1.1"
- whatwg-mimetype "^4.0.0"
- whatwg-url "^14.0.0"
- ws "^8.18.0"
- xml-name-validator "^5.0.0"
-
jsdom@^16.6.0:
version "16.7.0"
resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz"
@@ -8555,6 +8775,33 @@ jsdom@^16.6.0:
ws "^7.4.6"
xml-name-validator "^3.0.0"
+jsdom@^25.0.0:
+ version "25.0.1"
+ resolved "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz"
+ integrity sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==
+ dependencies:
+ cssstyle "^4.1.0"
+ data-urls "^5.0.0"
+ decimal.js "^10.4.3"
+ form-data "^4.0.0"
+ html-encoding-sniffer "^4.0.0"
+ http-proxy-agent "^7.0.2"
+ https-proxy-agent "^7.0.5"
+ is-potential-custom-element-name "^1.0.1"
+ nwsapi "^2.2.12"
+ parse5 "^7.1.2"
+ rrweb-cssom "^0.7.1"
+ saxes "^6.0.0"
+ symbol-tree "^3.2.4"
+ tough-cookie "^5.0.0"
+ w3c-xmlserializer "^5.0.0"
+ webidl-conversions "^7.0.0"
+ whatwg-encoding "^3.1.1"
+ whatwg-mimetype "^4.0.0"
+ whatwg-url "^14.0.0"
+ ws "^8.18.0"
+ xml-name-validator "^5.0.0"
+
jsesc@^3.0.2, jsesc@~3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz"
@@ -8707,13 +8954,6 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
-lie@~3.3.0:
- version "3.3.0"
- resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz"
- integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
- dependencies:
- immediate "~3.0.5"
-
lie@3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz"
@@ -8721,6 +8961,13 @@ lie@3.1.1:
dependencies:
immediate "~3.0.5"
+lie@~3.3.0:
+ version "3.3.0"
+ resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz"
+ integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
+ dependencies:
+ immediate "~3.0.5"
+
lighthouse-logger@^1.0.0:
version "1.4.2"
resolved "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz"
@@ -8729,12 +8976,57 @@ lighthouse-logger@^1.0.0:
debug "^2.6.9"
marky "^1.2.2"
+lightningcss-darwin-arm64@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz#565bd610533941cba648a70e105987578d82f996"
+ integrity sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==
+
+lightningcss-darwin-x64@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz#c906a267237b1c7fe08bff6c5ac032c099bc9482"
+ integrity sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==
+
+lightningcss-freebsd-x64@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz#a7c3c4d6ee18dffeb8fa69f14f8f9267f7dc0c34"
+ integrity sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==
+
+lightningcss-linux-arm-gnueabihf@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz#c7c16432a571ec877bf734fe500e4a43d48c2814"
+ integrity sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==
+
+lightningcss-linux-arm64-gnu@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz#cfd9e18df1cd65131da286ddacfa3aee6862a752"
+ integrity sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==
+
+lightningcss-linux-arm64-musl@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz#6682ff6b9165acef9a6796bd9127a8e1247bb0ed"
+ integrity sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==
+
+lightningcss-linux-x64-gnu@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz#714221212ad184ddfe974bbb7dbe9300dfde4bc0"
+ integrity sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==
+
+lightningcss-linux-x64-musl@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz#247958daf622a030a6dc2285afa16b7184bdf21e"
+ integrity sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==
+
+lightningcss-win32-arm64-msvc@1.27.0:
+ version "1.27.0"
+ resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz#64cfe473c264ef5dc275a4d57a516d77fcac6bc9"
+ integrity sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==
+
lightningcss-win32-x64-msvc@1.27.0:
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==
-lightningcss@^1.21.0, lightningcss@~1.27.0:
+lightningcss@~1.27.0:
version "1.27.0"
resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.27.0.tgz"
integrity sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==
@@ -8893,14 +9185,7 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
-magic-string@^0.25.0:
- version "0.25.9"
- resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz"
- integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
- dependencies:
- sourcemap-codec "^1.4.8"
-
-magic-string@^0.25.7:
+magic-string@^0.25.0, magic-string@^0.25.7:
version "0.25.9"
resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz"
integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
@@ -9054,7 +9339,7 @@ metro-cache@0.81.5:
flow-enums-runtime "^0.0.6"
metro-core "0.81.5"
-metro-config@^0.81.0, metro-config@0.81.5:
+metro-config@0.81.5, metro-config@^0.81.0:
version "0.81.5"
resolved "https://registry.npmjs.org/metro-config/-/metro-config-0.81.5.tgz"
integrity sha512-oDRAzUvj6RNRxratFdcVAqtAsg+T3qcKrGdqGZFUdwzlFJdHGR9Z413sW583uD2ynsuOjA2QB6US8FdwiBdNKg==
@@ -9068,7 +9353,7 @@ metro-config@^0.81.0, metro-config@0.81.5:
metro-core "0.81.5"
metro-runtime "0.81.5"
-metro-core@^0.81.0, metro-core@0.81.5:
+metro-core@0.81.5, metro-core@^0.81.0:
version "0.81.5"
resolved "https://registry.npmjs.org/metro-core/-/metro-core-0.81.5.tgz"
integrity sha512-+2R0c8ByfV2N7CH5wpdIajCWa8escUFd8TukfoXyBq/vb6yTCsznoA25FhNXJ+MC/cz1L447Zj3vdUfCXIZBwg==
@@ -9107,7 +9392,7 @@ metro-resolver@0.81.5:
dependencies:
flow-enums-runtime "^0.0.6"
-metro-runtime@^0.81.0, metro-runtime@0.81.5:
+metro-runtime@0.81.5, metro-runtime@^0.81.0:
version "0.81.5"
resolved "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.81.5.tgz"
integrity sha512-M/Gf71ictUKP9+77dV/y8XlAWg7xl76uhU7ggYFUwEdOHHWPG6gLBr1iiK0BmTjPFH8yRo/xyqMli4s3oGorPQ==
@@ -9115,7 +9400,7 @@ metro-runtime@^0.81.0, metro-runtime@0.81.5:
"@babel/runtime" "^7.25.0"
flow-enums-runtime "^0.0.6"
-metro-source-map@^0.81.0, metro-source-map@0.81.5:
+metro-source-map@0.81.5, metro-source-map@^0.81.0:
version "0.81.5"
resolved "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.81.5.tgz"
integrity sha512-Jz+CjvCKLNbJZYJTBeN3Kq9kIJf6b61MoLBdaOQZJ5Ajhw6Pf95Nn21XwA8BwfUYgajsi6IXsp/dTZsYJbN00Q==
@@ -9174,7 +9459,7 @@ metro-transform-worker@0.81.5:
metro-transform-plugins "0.81.5"
nullthrows "^1.1.1"
-metro@^0.81.0, metro@0.81.5:
+metro@0.81.5, metro@^0.81.0:
version "0.81.5"
resolved "https://registry.npmjs.org/metro/-/metro-0.81.5.tgz"
integrity sha512-YpFF0DDDpDVygeca2mAn7K0+us+XKmiGk4rIYMz/CRdjFoCGqAei/IQSpV0UrGfQbToSugpMQeQJveaWSH88Hg==
@@ -9228,16 +9513,16 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8:
braces "^3.0.3"
picomatch "^2.3.1"
-mime-db@^1.54.0, "mime-db@>= 1.43.0 < 2":
- version "1.54.0"
- resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
- integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
-
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+"mime-db@>= 1.43.0 < 2", mime-db@^1.54.0:
+ version "1.54.0"
+ resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
+ integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
+
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34, mime-types@~2.1.35:
version "2.1.35"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
@@ -9332,16 +9617,16 @@ minipass@^3.0.0:
dependencies:
yallist "^4.0.0"
-"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3, minipass@^7.1.2:
- version "7.1.3"
- resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz"
- integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==
-
minipass@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz"
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3, minipass@^7.1.2:
+ version "7.1.3"
+ resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz"
+ integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==
+
minizlib@^2.1.1:
version "2.1.2"
resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz"
@@ -9357,26 +9642,21 @@ mkdirp@^0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "^1.2.6"
-mkdirp@^1.0.3:
+mkdirp@^1.0.3, mkdirp@^1.0.4:
version "1.0.4"
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-mkdirp@^1.0.4:
- version "1.0.4"
- resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
- integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-
-ms@^2.1.1, ms@^2.1.3, ms@2.1.3:
- version "2.1.3"
- resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
- integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-
ms@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+ms@2.1.3, ms@^2.1.1, ms@^2.1.3:
+ version "2.1.3"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
multicast-dns@^7.2.5:
version "7.2.5"
resolved "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz"
@@ -9409,16 +9689,16 @@ natural-compare@^1.4.0:
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
-negotiator@~0.6.4:
- version "0.6.4"
- resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz"
- integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==
-
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+negotiator@~0.6.4:
+ version "0.6.4"
+ resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz"
+ integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==
+
neo-async@^2.5.0, neo-async@^2.6.2:
version "2.6.2"
resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz"
@@ -9742,14 +10022,7 @@ p-limit@^2.0.0, p-limit@^2.2.0:
dependencies:
p-try "^2.0.0"
-p-limit@^3.0.2:
- version "3.1.0"
- resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
- integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
- dependencies:
- yocto-queue "^0.1.0"
-
-p-limit@^3.1.0:
+p-limit@^3.0.2, p-limit@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
@@ -9847,6 +10120,11 @@ parse-png@^2.1.0:
dependencies:
pngjs "^3.3.0"
+parse5@6.0.1:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz"
+ integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
+
parse5@^7.1.2:
version "7.3.0"
resolved "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz"
@@ -9854,11 +10132,6 @@ parse5@^7.1.2:
dependencies:
entities "^6.0.0"
-parse5@6.0.1:
- version "6.0.1"
- resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz"
- integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
-
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz"
@@ -9892,12 +10165,7 @@ path-key@^2.0.0, path-key@^2.0.1:
resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz"
integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==
-path-key@^3.0.0:
- version "3.1.1"
- resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
- integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-
-path-key@^3.1.0:
+path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
@@ -9967,16 +10235,16 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatc
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz"
integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==
-"picomatch@^3 || ^4", picomatch@^4.0.2, picomatch@^4.0.4:
- version "4.0.4"
- resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz"
- integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==
-
picomatch@^3.0.1:
version "3.0.2"
resolved "https://registry.npmjs.org/picomatch/-/picomatch-3.0.2.tgz"
integrity sha512-cfDHL6LStTEKlNilboNtobT/kEa30PtAf2Q1OgszfrG/rpVl1xaFWT9ktfkS306GmHgmnad1Sw4wabhlvFtsTw==
+picomatch@^4.0.2, picomatch@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz"
+ integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==
+
pify@^2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
@@ -10574,15 +10842,6 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
-"postcss@^7.0.0 || ^8.0.1", postcss@^8, postcss@^8.0.0, postcss@^8.0.3, postcss@^8.0.9, postcss@^8.1.0, postcss@^8.1.4, postcss@^8.2, postcss@^8.2.14, postcss@^8.2.15, postcss@^8.2.2, postcss@^8.3, postcss@^8.3.5, postcss@^8.4, postcss@^8.4.21, postcss@^8.4.33, postcss@^8.4.4, postcss@^8.4.43, postcss@^8.4.47, postcss@^8.4.6, postcss@^8.5.3, "postcss@>= 8", postcss@>=8, postcss@>=8.0.9:
- version "8.5.15"
- resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz"
- integrity sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==
- dependencies:
- nanoid "^3.3.12"
- picocolors "^1.1.1"
- source-map-js "^1.2.1"
-
postcss@^7.0.35:
version "7.0.39"
resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz"
@@ -10591,6 +10850,15 @@ postcss@^7.0.35:
picocolors "^0.2.1"
source-map "^0.6.1"
+postcss@^8.3.5, postcss@^8.4.33, postcss@^8.4.4, postcss@^8.4.43, postcss@^8.4.47, postcss@^8.5.3:
+ version "8.5.15"
+ resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz"
+ integrity sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==
+ dependencies:
+ nanoid "^3.3.12"
+ picocolors "^1.1.1"
+ source-map-js "^1.2.1"
+
postcss@~8.4.32:
version "8.4.49"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz"
@@ -10858,7 +11126,7 @@ react-devtools-core@^5.3.1:
shell-quote "^1.6.1"
ws "^7"
-"react-dom@^18.0.0 || ^19.0.0", react-dom@^18.2.0, react-dom@^19.0.0, react-dom@>=18:
+react-dom@^19.0.0:
version "19.2.6"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz"
integrity sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==
@@ -10930,12 +11198,12 @@ react-native-reanimated@~3.16.0:
convert-source-map "^2.0.0"
invariant "^2.2.4"
-"react-native-safe-area-context@>= 4.0.0", react-native-safe-area-context@4.14.1:
+react-native-safe-area-context@4.14.1:
version "4.14.1"
resolved "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.14.1.tgz"
integrity sha512-+tUhT5WBl8nh5+P+chYhAjR470iCByf9z5EYdCEbPaAK3Yfzw+o8VRPnUgmPAKlSccOgQBxx3NOl/Wzckn9ujg==
-"react-native-screens@>= 4.0.0", react-native-screens@~4.4.0:
+react-native-screens@~4.4.0:
version "4.4.0"
resolved "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.4.0.tgz"
integrity sha512-c7zc7Zwjty6/pGyuuvh9gK3YBYqHPOxrhXfG1lF4gHlojQSmIx2piNbNaV+Uykj+RDTmFXK0e/hA+fucw/Qozg==
@@ -10943,7 +11211,15 @@ react-native-reanimated@~3.16.0:
react-freeze "^1.0.0"
warn-once "^0.1.0"
-react-native@*, "react-native@^0.0.0-0 || >=0.65 <1.0", react-native@0.76.6:
+react-native-webview@13.12.5:
+ version "13.12.5"
+ resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-13.12.5.tgz#ed9eec1eda234d7cf18d329859b9bdebf7e258b6"
+ integrity sha512-INOKPom4dFyzkbxbkuQNfeRG9/iYnyRDzrDkJeyvSWgJAW2IDdJkWFJBS2v0RxIL4gqLgHkiIZDOfiLaNnw83Q==
+ dependencies:
+ escape-string-regexp "^4.0.0"
+ invariant "2.2.4"
+
+react-native@0.76.6:
version "0.76.6"
resolved "https://registry.npmjs.org/react-native/-/react-native-0.76.6.tgz"
integrity sha512-AsRi+ud6v6ADH7ZtSOY42kRB4nbM0KtSu450pGO4pDudl4AEK/AF96ai88snb2/VJJSGGa/49QyJVFXxz/qoFg==
@@ -10995,7 +11271,7 @@ react-reader@^2.0.15:
epubjs "^0.3.93"
react-swipeable "^7.0.2"
-react-refresh@^0.11.0, "react-refresh@>=0.10.0 <1.0.0":
+react-refresh@^0.11.0:
version "0.11.0"
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz"
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
@@ -11085,7 +11361,7 @@ react-swipeable@^7.0.2:
resolved "https://registry.npmjs.org/react-swipeable/-/react-swipeable-7.0.2.tgz"
integrity sha512-v1Qx1l+aC2fdxKa9aKJiaU/ZxmJ5o98RMoFwUqAAzVWUcxgfHFXDDruCKXhw6zIYXm6V64JiHgP9f6mlME5l8w==
-react@*, "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.3 || ^17 || ^18 || ^19.0.0 || ^19.0.0-rc", "react@^18.0.0 || ^19.0.0", react@^18.2.0, react@^19.0.0, react@^19.2.6, "react@>= 16", "react@>= 18.2.0", react@>=16.8, react@>=17.0.0, react@>=18:
+react@^19.0.0:
version "19.2.6"
resolved "https://registry.npmjs.org/react/-/react-19.2.6.tgz"
integrity sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==
@@ -11331,19 +11607,7 @@ resolve@^1.1.7, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.11, resolve@^1.2
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
-resolve@^2.0.0-next.5:
- version "2.0.0-next.7"
- resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz"
- integrity sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==
- dependencies:
- es-errors "^1.3.0"
- is-core-module "^2.16.2"
- node-exports-info "^1.6.0"
- object-keys "^1.1.1"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
-resolve@^2.0.0-next.6:
+resolve@^2.0.0-next.5, resolve@^2.0.0-next.6:
version "2.0.0-next.7"
resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz"
integrity sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==
@@ -11404,48 +11668,14 @@ rollup-plugin-terser@^7.0.0:
serialize-javascript "^4.0.0"
terser "^5.0.0"
-"rollup@^1.20.0 || ^2.0.0", rollup@^1.20.0||^2.0.0, rollup@^2.0.0, rollup@^2.43.1:
+rollup@^2.43.1:
version "2.80.0"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz"
integrity sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==
optionalDependencies:
fsevents "~2.3.2"
-rollup@^4.20.0:
- version "4.60.4"
- resolved "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz"
- integrity sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==
- dependencies:
- "@types/estree" "1.0.8"
- optionalDependencies:
- "@rollup/rollup-android-arm-eabi" "4.60.4"
- "@rollup/rollup-android-arm64" "4.60.4"
- "@rollup/rollup-darwin-arm64" "4.60.4"
- "@rollup/rollup-darwin-x64" "4.60.4"
- "@rollup/rollup-freebsd-arm64" "4.60.4"
- "@rollup/rollup-freebsd-x64" "4.60.4"
- "@rollup/rollup-linux-arm-gnueabihf" "4.60.4"
- "@rollup/rollup-linux-arm-musleabihf" "4.60.4"
- "@rollup/rollup-linux-arm64-gnu" "4.60.4"
- "@rollup/rollup-linux-arm64-musl" "4.60.4"
- "@rollup/rollup-linux-loong64-gnu" "4.60.4"
- "@rollup/rollup-linux-loong64-musl" "4.60.4"
- "@rollup/rollup-linux-ppc64-gnu" "4.60.4"
- "@rollup/rollup-linux-ppc64-musl" "4.60.4"
- "@rollup/rollup-linux-riscv64-gnu" "4.60.4"
- "@rollup/rollup-linux-riscv64-musl" "4.60.4"
- "@rollup/rollup-linux-s390x-gnu" "4.60.4"
- "@rollup/rollup-linux-x64-gnu" "4.60.4"
- "@rollup/rollup-linux-x64-musl" "4.60.4"
- "@rollup/rollup-openbsd-x64" "4.60.4"
- "@rollup/rollup-openharmony-arm64" "4.60.4"
- "@rollup/rollup-win32-arm64-msvc" "4.60.4"
- "@rollup/rollup-win32-ia32-msvc" "4.60.4"
- "@rollup/rollup-win32-x64-gnu" "4.60.4"
- "@rollup/rollup-win32-x64-msvc" "4.60.4"
- fsevents "~2.3.2"
-
-rollup@^4.34.9:
+rollup@^4.20.0, rollup@^4.34.9:
version "4.60.4"
resolved "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz"
integrity sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==
@@ -11507,17 +11737,12 @@ safe-array-concat@^1.1.3:
has-symbols "^1.1.0"
isarray "^2.0.5"
-safe-buffer@^5.1.0, safe-buffer@>=5.1.0, safe-buffer@~5.2.0, safe-buffer@5.2.1:
+safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
-safe-buffer@~5.1.0:
- version "5.1.2"
- resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
- integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-safe-buffer@~5.1.1:
+safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
@@ -11557,7 +11782,7 @@ sass-loader@^12.3.0:
klona "^2.0.4"
neo-async "^2.6.2"
-sax@^1.5.0, sax@>=0.6.0:
+sax@>=0.6.0, sax@^1.5.0:
version "1.6.0"
resolved "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz"
integrity sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==
@@ -11581,11 +11806,6 @@ saxes@^6.0.0:
dependencies:
xmlchars "^2.2.0"
-scheduler@^0.27.0:
- version "0.27.0"
- resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz"
- integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==
-
scheduler@0.24.0-canary-efb381bbf-20230505:
version "0.24.0-canary-efb381bbf-20230505"
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz"
@@ -11593,6 +11813,20 @@ scheduler@0.24.0-canary-efb381bbf-20230505:
dependencies:
loose-envify "^1.1.0"
+scheduler@^0.27.0:
+ version "0.27.0"
+ resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz"
+ integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==
+
+schema-utils@2.7.0:
+ version "2.7.0"
+ resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz"
+ integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==
+ dependencies:
+ "@types/json-schema" "^7.0.4"
+ ajv "^6.12.2"
+ ajv-keywords "^3.4.1"
+
schema-utils@^2.6.5:
version "2.7.1"
resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz"
@@ -11621,15 +11855,6 @@ schema-utils@^4.0.0, schema-utils@^4.2.0, schema-utils@^4.3.0, schema-utils@^4.3
ajv-formats "^2.1.1"
ajv-keywords "^5.1.0"
-schema-utils@2.7.0:
- version "2.7.0"
- resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz"
- integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==
- dependencies:
- "@types/json-schema" "^7.0.4"
- ajv "^6.12.2"
- ajv-keywords "^3.4.1"
-
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz"
@@ -11643,27 +11868,12 @@ selfsigned@^2.1.1, selfsigned@^2.4.1:
"@types/node-forge" "^1.3.0"
node-forge "^1"
-semver@^5.5.0:
+semver@^5.5.0, semver@^5.6.0:
version "5.7.2"
resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
-semver@^5.6.0:
- version "5.7.2"
- resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
- integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
-
-semver@^6.0.0:
- version "6.3.1"
- resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
- integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-
-semver@^6.3.0:
- version "6.3.1"
- resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
- integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-
-semver@^6.3.1:
+semver@^6.0.0, semver@^6.3.0, semver@^6.3.1:
version "6.3.1"
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
@@ -11775,7 +11985,7 @@ setimmediate@^1.0.5:
resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz"
integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
-setprototypeof@~1.2.0, setprototypeof@1.2.0:
+setprototypeof@1.2.0, setprototypeof@~1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
@@ -11948,16 +12158,16 @@ source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.2
buffer-from "^1.0.0"
source-map "^0.6.0"
+source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1, source-map@0.6.1:
- version "0.6.1"
- resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
- integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-
source-map@^0.7.3:
version "0.7.6"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz"
@@ -12051,12 +12261,7 @@ static-eval@2.1.1:
dependencies:
escodegen "^2.1.0"
-"statuses@>= 1.5.0 < 2":
- version "1.5.0"
- resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz"
- integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
-
-statuses@~1.5.0:
+"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
@@ -12079,7 +12284,7 @@ stop-iteration-iterator@^1.1.0:
es-errors "^1.3.0"
internal-slot "^1.1.0"
-stream-buffers@~2.2.0, stream-buffers@2.2.x:
+stream-buffers@2.2.x, stream-buffers@~2.2.0:
version "2.2.0"
resolved "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==
@@ -12089,20 +12294,6 @@ strict-uri-encode@^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==
-string_decoder@^1.1.1:
- version "1.3.0"
- resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
- integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
- dependencies:
- safe-buffer "~5.2.0"
-
-string_decoder@~1.1.1:
- version "1.1.1"
- resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
- integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
- dependencies:
- safe-buffer "~5.1.0"
-
string-length@^4.0.1:
version "4.0.2"
resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz"
@@ -12219,6 +12410,20 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
stringify-object@^3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz"
@@ -12316,19 +12521,6 @@ stylehacks@^5.1.1:
browserslist "^4.21.4"
postcss-selector-parser "^6.0.4"
-sucrase@^3.35.0:
- version "3.35.1"
- resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz"
- integrity sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==
- dependencies:
- "@jridgewell/gen-mapping" "^0.3.2"
- commander "^4.0.0"
- lines-and-columns "^1.1.6"
- mz "^2.7.0"
- pirates "^4.0.1"
- tinyglobby "^0.2.11"
- ts-interface-checker "^0.1.9"
-
sucrase@3.35.0:
version "3.35.0"
resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz"
@@ -12342,6 +12534,19 @@ sucrase@3.35.0:
pirates "^4.0.1"
ts-interface-checker "^0.1.9"
+sucrase@^3.35.0:
+ version "3.35.1"
+ resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz"
+ integrity sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.2"
+ commander "^4.0.0"
+ lines-and-columns "^1.1.6"
+ mz "^2.7.0"
+ pirates "^4.0.1"
+ tinyglobby "^0.2.11"
+ ts-interface-checker "^0.1.9"
+
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
@@ -12519,7 +12724,7 @@ terser-webpack-plugin@^5.2.5, terser-webpack-plugin@^5.5.0:
schema-utils "^4.3.0"
terser "^5.31.1"
-terser@^5.0.0, terser@^5.10.0, terser@^5.15.0, terser@^5.16.0, terser@^5.31.1, terser@^5.4.0:
+terser@^5.0.0, terser@^5.10.0, terser@^5.15.0, terser@^5.31.1:
version "5.48.0"
resolved "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz"
integrity sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==
@@ -12637,7 +12842,7 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
-toidentifier@~1.0.1, toidentifier@1.0.1:
+toidentifier@1.0.1, toidentifier@~1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
@@ -12734,7 +12939,7 @@ type-detect@4.0.8:
resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
-type-fest@^0.16.0, "type-fest@>=0.17.0 <5.0.0":
+type-fest@^0.16.0:
version "0.16.0"
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz"
integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==
@@ -12819,7 +13024,7 @@ typedarray-to-buffer@^3.1.5:
dependencies:
is-typedarray "^1.0.0"
-"typescript@^3.2.1 || ^4", "typescript@>= 2.7", "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@~5.7.0:
+typescript@~5.7.0:
version "5.7.3"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz"
integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
@@ -13031,18 +13236,6 @@ vite-node@2.1.9:
pathe "^1.1.2"
vite "^5.0.0"
-"vite@^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0":
- version "6.4.2"
- dependencies:
- esbuild "^0.25.0"
- fdir "^6.4.4"
- picomatch "^4.0.2"
- postcss "^8.5.3"
- rollup "^4.34.9"
- tinyglobby "^0.2.13"
- optionalDependencies:
- fsevents "~2.3.3"
-
vite@^5.0.0:
version "5.4.21"
resolved "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz"
@@ -13195,7 +13388,7 @@ webpack-dev-middleware@^5.3.4:
range-parser "^1.2.1"
schema-utils "^4.0.0"
-webpack-dev-server@^4.6.0, "webpack-dev-server@3.x || 4.x || 5.x":
+webpack-dev-server@^4.6.0:
version "4.15.2"
resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz"
integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==
@@ -13260,7 +13453,7 @@ webpack-sources@^3.5.0:
resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz"
integrity sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==
-"webpack@^4.0.0 || ^5.0.0", "webpack@^4.37.0 || ^5.0.0", "webpack@^4.4.0 || ^5.9.0", "webpack@^4.44.2 || ^5.47.0", webpack@^5.0.0, webpack@^5.1.0, webpack@^5.20.0, webpack@^5.64.4, "webpack@>= 4", webpack@>=2, "webpack@>=4.43.0 <6.0.0":
+webpack@^5.64.4:
version "5.107.2"
resolved "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz"
integrity sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==
@@ -13289,7 +13482,7 @@ webpack-sources@^3.5.0:
watchpack "^2.5.1"
webpack-sources "^3.5.0"
-websocket-driver@^0.7.4, websocket-driver@>=0.5.1:
+websocket-driver@>=0.5.1, websocket-driver@^0.7.4:
version "0.7.4"
resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz"
integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==
@@ -13695,32 +13888,12 @@ ws@^6.2.3:
dependencies:
async-limiter "~1.0.0"
-ws@^7:
+ws@^7, ws@^7.4.6, ws@^7.5.10:
version "7.5.11"
resolved "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz"
integrity sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==
-ws@^7.4.6:
- version "7.5.11"
- resolved "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz"
- integrity sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==
-
-ws@^7.5.10:
- version "7.5.11"
- resolved "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz"
- integrity sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==
-
-ws@^8.12.1:
- version "8.21.0"
- resolved "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz"
- integrity sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==
-
-ws@^8.13.0:
- version "8.21.0"
- resolved "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz"
- integrity sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==
-
-ws@^8.18.0:
+ws@^8.12.1, ws@^8.13.0, ws@^8.18.0:
version "8.21.0"
resolved "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz"
integrity sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==
@@ -13786,7 +13959,7 @@ yallist@^4.0.0:
resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2, yaml@^2.4.2:
+yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
version "1.10.3"
resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz"
integrity sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==