diff --git a/.env b/.env
new file mode 100644
index 0000000..5f969f5
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+EXPO_PUBLIC_SENTRY_DSN=https://bdb940f3a950ee46ce8ba651dee9b433@o4511094585819136.ingest.de.sentry.io/4511094601810000
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 29ed2b0..1e88ecf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,4 +48,5 @@ CLAUDE.md
docs/
feature.md
livePlan.md
-Promotion.md
\ No newline at end of file
+Promotion.md
+.env.local
diff --git a/App.tsx b/App.tsx
index 0329d0c..b81b559 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,14 +1,34 @@
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
+import * as Sentry from '@sentry/react-native';
-export default function App() {
+Sentry.init({
+ dsn: 'https://bdb940f3a950ee46ce8ba651dee9b433@o4511094585819136.ingest.de.sentry.io/4511094601810000',
+
+ // Adds more context data to events (IP address, cookies, user, etc.)
+ // For more information, visit: https://docs.sentry.io/platforms/react-native/data-management/data-collected/
+ sendDefaultPii: true,
+
+ // Enable Logs
+ enableLogs: true,
+
+ // Configure Session Replay
+ replaysSessionSampleRate: 0.1,
+ replaysOnErrorSampleRate: 1,
+ integrations: [Sentry.mobileReplayIntegration(), Sentry.feedbackIntegration()],
+
+ // uncomment the line below to enable Spotlight (https://spotlightjs.com)
+ // spotlight: __DEV__,
+});
+
+export default Sentry.wrap(function App() {
return (
Open up App.tsx to start working on your app!
);
-}
+});
const styles = StyleSheet.create({
container: {
diff --git a/app.json b/app.json
index ffec55f..8ac1444 100644
--- a/app.json
+++ b/app.json
@@ -1,7 +1,7 @@
{
"expo": {
"name": "JKVideo",
- "slug": "jkvideo",
+ "slug": "jsvideo",
"version": "1.0.5",
"scheme": "bilibili",
"orientation": "default",
@@ -24,6 +24,9 @@
},
"predictiveBackGestureEnabled": false,
"permissions": [
+ "android.permission.RECORD_AUDIO",
+ "android.permission.MODIFY_AUDIO_SETTINGS",
+ "android.permission.REQUEST_INSTALL_PACKAGES",
"android.permission.RECORD_AUDIO",
"android.permission.MODIFY_AUDIO_SETTINGS",
"android.permission.REQUEST_INSTALL_PACKAGES"
@@ -37,10 +40,27 @@
"plugins": [
"expo-router",
"react-native-video",
- "expo-screen-orientation"
+ "expo-screen-orientation",
+ "expo-updates",
+ "@sentry/react-native/expo"
],
"experiments": {
"typedRoutes": true
- }
+ },
+ "runtimeVersion": {
+ "policy": "appVersion"
+ },
+ "updates": {
+ "url": "https://u.expo.dev/eac4192a-ae80-461c-8fff-6e1a8b777bd1",
+ "checkAutomatically": "ON_LOAD",
+ "fallbackToCacheTimeout": 0
+ },
+ "extra": {
+ "router": {},
+ "eas": {
+ "projectId": "eac4192a-ae80-461c-8fff-6e1a8b777bd1"
+ }
+ },
+ "owner": "jinsha"
}
}
diff --git a/app/_layout.tsx b/app/_layout.tsx
index d602dc7..bb2fbc3 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -1,14 +1,24 @@
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import { SafeAreaProvider } from 'react-native-safe-area-context';
-import { View } from 'react-native';
+import { Text, View } from 'react-native';
import { useEffect } from 'react';
import { useAuthStore } from '../store/authStore';
import { useDownloadStore } from '../store/downloadStore';
import { useSettingsStore } from '../store/settingsStore';
import { MiniPlayer } from '../components/MiniPlayer';
+import * as Updates from 'expo-updates';
+import * as Sentry from '@sentry/react-native';
+import { ErrorBoundary } from '@sentry/react-native';
-export default function RootLayout() {
+Sentry.init({
+ dsn: process.env.EXPO_PUBLIC_SENTRY_DSN ?? '',
+ enabled: !__DEV__,
+ tracesSampleRate: 0.05,
+ environment: process.env.EXPO_PUBLIC_APP_ENV ?? 'production',
+});
+
+function RootLayout() {
const restore = useAuthStore(s => s.restore);
const loadDownloads = useDownloadStore(s => s.loadFromStorage);
const restoreSettings = useSettingsStore(s => s.restore);
@@ -17,56 +27,73 @@ export default function RootLayout() {
restore();
loadDownloads();
restoreSettings();
+
+ const checkOTA = async () => {
+ if (!Updates.isEnabled) return;
+ try {
+ const update = await Updates.checkForUpdateAsync();
+ if (update.isAvailable) {
+ await Updates.fetchUpdateAsync();
+ }
+ } catch {
+ // 静默失败,不影响正常使用
+ }
+ };
+ checkOTA();
}, []);
return (
-
-
-
-
-
-
-
-
+ 发生错误,请重启 App}>
+
+
+
+
+
+
+
+
+
);
}
+
+export default Sentry.wrap(RootLayout);
diff --git a/eas.json b/eas.json
new file mode 100644
index 0000000..ba470c6
--- /dev/null
+++ b/eas.json
@@ -0,0 +1,28 @@
+{
+ "cli": {
+ "version": ">= 16.0.0"
+ },
+ "build": {
+ "development": {
+ "developmentClient": true,
+ "distribution": "internal",
+ "channel": "development"
+ },
+ "preview": {
+ "distribution": "internal",
+ "channel": "preview"
+ },
+ "production": {
+ "channel": "production",
+ "env": {
+ "EXPO_PUBLIC_APP_ENV": "production",
+ "SENTRY_AUTH_TOKEN": "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",
+ "SENTRY_ORG": "your-org-slug",
+ "SENTRY_PROJECT": "your-project-slug"
+ }
+ }
+ },
+ "submit": {
+ "production": {}
+ }
+}
diff --git a/metro.config.js b/metro.config.js
new file mode 100644
index 0000000..9d82ec1
--- /dev/null
+++ b/metro.config.js
@@ -0,0 +1,23 @@
+const path = require('path');
+const {
+ getSentryExpoConfig
+} = require("@sentry/react-native/metro");
+
+const config = getSentryExpoConfig(__dirname);
+
+const originalResolveRequest = config.resolver.resolveRequest;
+
+config.resolver.resolveRequest = (context, moduleName, platform) => {
+ if (platform === 'web' && moduleName === 'react-native-pager-view') {
+ return {
+ filePath: path.resolve(__dirname, 'shims/react-native-pager-view.web.tsx'),
+ type: 'sourceFile',
+ };
+ }
+ if (originalResolveRequest) {
+ return originalResolveRequest(context, moduleName, platform);
+ }
+ return context.resolveRequest(context, moduleName, platform);
+};
+
+module.exports = config;
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 9e597df..dccf46f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,17 @@
{
"name": "jkvideo",
- "version": "1.0.0",
+ "version": "1.0.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "jkvideo",
- "version": "1.0.0",
+ "version": "1.0.5",
"dependencies": {
"@dr.pogodin/react-native-static-server": "^0.26.0",
"@expo/vector-icons": "^15.0.2",
"@react-native-async-storage/async-storage": "2.2.0",
+ "@sentry/react-native": "~7.11.0",
"axios": "^1.13.6",
"expo": "~55.0.5",
"expo-av": "^16.0.8",
@@ -26,6 +27,7 @@
"expo-screen-orientation": "~55.0.8",
"expo-status-bar": "~55.0.4",
"expo-system-ui": "~55.0.9",
+ "expo-updates": "~55.0.15",
"pako": "^2.1.0",
"react": "19.2.0",
"react-dom": "19.2.0",
@@ -2924,6 +2926,335 @@
"nanoid": "^3.3.11"
}
},
+ "node_modules/@sentry-internal/browser-utils": {
+ "version": "10.37.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.37.0.tgz",
+ "integrity": "sha512-rqdESYaVio9Ktz55lhUhtBsBUCF3wvvJuWia5YqoHDd+egyIfwWxITTAa0TSEyZl7283A4WNHNl0hyeEMblmfA==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/core": "10.37.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry-internal/feedback": {
+ "version": "10.37.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.37.0.tgz",
+ "integrity": "sha512-P0PVlfrDvfvCYg2KPIS7YUG/4i6ZPf8z1MicXx09C9Cz9W9UhSBh/nii13eBdDtLav2BFMKhvaFMcghXHX03Hw==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/core": "10.37.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry-internal/replay": {
+ "version": "10.37.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.37.0.tgz",
+ "integrity": "sha512-snuk12ZaDerxesSnetNIwKoth/51R0y/h3eXD/bGtXp+hnSkeXN5HanI/RJl297llRjn4zJYRShW9Nx86Ay0Dw==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/browser-utils": "10.37.0",
+ "@sentry/core": "10.37.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry-internal/replay-canvas": {
+ "version": "10.37.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.37.0.tgz",
+ "integrity": "sha512-PyIYSbjLs+L5essYV0MyIsh4n5xfv2eV7l0nhUoPJv9Bak3kattQY3tholOj0EP3SgKgb+8HSZnmazgF++Hbog==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/replay": "10.37.0",
+ "@sentry/core": "10.37.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry/babel-plugin-component-annotate": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-4.8.0.tgz",
+ "integrity": "sha512-cy/9Eipkv23MsEJ4IuB4dNlVwS9UqOzI3Eu+QPake5BVFgPYCX0uP0Tr3Z43Ime6Rb+BiDnWC51AJK9i9afHYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/@sentry/browser": {
+ "version": "10.37.0",
+ "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.37.0.tgz",
+ "integrity": "sha512-kheqJNqGZP5TSBCPv4Vienv1sfZwXKHQDYR+xrdHHYdZqwWuZMJJW/cLO9XjYAe+B9NnJ4UwJOoY4fPvU+HQ1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/browser-utils": "10.37.0",
+ "@sentry-internal/feedback": "10.37.0",
+ "@sentry-internal/replay": "10.37.0",
+ "@sentry-internal/replay-canvas": "10.37.0",
+ "@sentry/core": "10.37.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry/cli": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.58.4.tgz",
+ "integrity": "sha512-ArDrpuS8JtDYEvwGleVE+FgR+qHaOp77IgdGSacz6SZy6Lv90uX0Nu4UrHCQJz8/xwIcNxSqnN22lq0dH4IqTg==",
+ "hasInstallScript": true,
+ "license": "FSL-1.1-MIT",
+ "dependencies": {
+ "https-proxy-agent": "^5.0.0",
+ "node-fetch": "^2.6.7",
+ "progress": "^2.0.3",
+ "proxy-from-env": "^1.1.0",
+ "which": "^2.0.2"
+ },
+ "bin": {
+ "sentry-cli": "bin/sentry-cli"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@sentry/cli-darwin": "2.58.4",
+ "@sentry/cli-linux-arm": "2.58.4",
+ "@sentry/cli-linux-arm64": "2.58.4",
+ "@sentry/cli-linux-i686": "2.58.4",
+ "@sentry/cli-linux-x64": "2.58.4",
+ "@sentry/cli-win32-arm64": "2.58.4",
+ "@sentry/cli-win32-i686": "2.58.4",
+ "@sentry/cli-win32-x64": "2.58.4"
+ }
+ },
+ "node_modules/@sentry/cli-darwin": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.58.4.tgz",
+ "integrity": "sha512-kbTD+P4X8O+nsNwPxCywtj3q22ecyRHWff98rdcmtRrvwz8CKi/T4Jxn/fnn2i4VEchy08OWBuZAqaA5Kh2hRQ==",
+ "license": "FSL-1.1-MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@sentry/cli-linux-arm": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.58.4.tgz",
+ "integrity": "sha512-rdQ8beTwnN48hv7iV7e7ZKucPec5NJkRdrrycMJMZlzGBPi56LqnclgsHySJ6Kfq506A2MNuQnKGaf/sBC9REA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "FSL-1.1-MIT",
+ "optional": true,
+ "os": [
+ "linux",
+ "freebsd",
+ "android"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@sentry/cli-linux-arm64": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.58.4.tgz",
+ "integrity": "sha512-0g0KwsOozkLtzN8/0+oMZoOuQ0o7W6O+hx+ydVU1bktaMGKEJLMAWxOQNjsh1TcBbNIXVOKM/I8l0ROhaAb8Ig==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "FSL-1.1-MIT",
+ "optional": true,
+ "os": [
+ "linux",
+ "freebsd",
+ "android"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@sentry/cli-linux-i686": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.58.4.tgz",
+ "integrity": "sha512-NseoIQAFtkziHyjZNPTu1Gm1opeQHt7Wm1LbLrGWVIRvUOzlslO9/8i6wETUZ6TjlQxBVRgd3Q0lRBG2A8rFYA==",
+ "cpu": [
+ "x86",
+ "ia32"
+ ],
+ "license": "FSL-1.1-MIT",
+ "optional": true,
+ "os": [
+ "linux",
+ "freebsd",
+ "android"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@sentry/cli-linux-x64": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.58.4.tgz",
+ "integrity": "sha512-d3Arz+OO/wJYTqCYlSN3Ktm+W8rynQ/IMtSZLK8nu0ryh5mJOh+9XlXY6oDXw4YlsM8qCRrNquR8iEI1Y/IH+Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "FSL-1.1-MIT",
+ "optional": true,
+ "os": [
+ "linux",
+ "freebsd",
+ "android"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@sentry/cli-win32-arm64": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.58.4.tgz",
+ "integrity": "sha512-bqYrF43+jXdDBh0f8HIJU3tbvlOFtGyRjHB8AoRuMQv9TEDUfENZyCelhdjA+KwDKYl48R1Yasb4EHNzsoO83w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "FSL-1.1-MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@sentry/cli-win32-i686": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.58.4.tgz",
+ "integrity": "sha512-3triFD6jyvhVcXOmGyttf+deKZcC1tURdhnmDUIBkiDPJKGT/N5xa4qAtHJlAB/h8L9jgYih9bvJnvvFVM7yug==",
+ "cpu": [
+ "x86",
+ "ia32"
+ ],
+ "license": "FSL-1.1-MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@sentry/cli-win32-x64": {
+ "version": "2.58.4",
+ "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.58.4.tgz",
+ "integrity": "sha512-cSzN4PjM1RsCZ4pxMjI0VI7yNCkxiJ5jmWncyiwHXGiXrV1eXYdQ3n1LhUYLZ91CafyprR0OhDcE+RVZ26Qb5w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "FSL-1.1-MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@sentry/cli/node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/@sentry/cli/node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@sentry/core": {
+ "version": "10.37.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.37.0.tgz",
+ "integrity": "sha512-hkRz7S4gkKLgPf+p3XgVjVm7tAfvcEPZxeACCC6jmoeKhGkzN44nXwLiqqshJ25RMcSrhfFvJa/FlBg6zupz7g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry/react": {
+ "version": "10.37.0",
+ "resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.37.0.tgz",
+ "integrity": "sha512-XLnXJOHgsCeVAVBbO+9AuGlZWnCxLQHLOmKxpIr8wjE3g7dHibtug6cv8JLx78O4dd7aoCqv2TTyyKY9FLJ2EQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/browser": "10.37.0",
+ "@sentry/core": "10.37.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^16.14.0 || 17.x || 18.x || 19.x"
+ }
+ },
+ "node_modules/@sentry/react-native": {
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-7.11.0.tgz",
+ "integrity": "sha512-OiDaLCAGpRN18YG/o7IIwLhU0Xpb0tYKQ5QxkGHiwb+L3VHn+MqGCGfITYNdhqr06HHMvu9Lysm+UJxaNmGaJg==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/babel-plugin-component-annotate": "4.8.0",
+ "@sentry/browser": "10.37.0",
+ "@sentry/cli": "2.58.4",
+ "@sentry/core": "10.37.0",
+ "@sentry/react": "10.37.0",
+ "@sentry/types": "10.37.0"
+ },
+ "bin": {
+ "sentry-expo-upload-sourcemaps": "scripts/expo-upload-sourcemaps.js"
+ },
+ "peerDependencies": {
+ "expo": ">=49.0.0",
+ "react": ">=17.0.0",
+ "react-native": ">=0.65.0"
+ },
+ "peerDependenciesMeta": {
+ "expo": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@sentry/types": {
+ "version": "10.37.0",
+ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-10.37.0.tgz",
+ "integrity": "sha512-umpnUKRC0AAbJrADg6SlFtqN2yzf7NHciCF9lkHau+ax2PIZ/NDmoG4RQujFVflVaVoD60Ly2t+CcPnYIWMPlw==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/core": "10.37.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@sinclair/typebox": {
"version": "0.27.10",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz",
@@ -4517,6 +4848,12 @@
"expo": "*"
}
},
+ "node_modules/expo-eas-client": {
+ "version": "55.0.2",
+ "resolved": "https://registry.npmjs.org/expo-eas-client/-/expo-eas-client-55.0.2.tgz",
+ "integrity": "sha512-fjOgSXaZFBK2Xmzn/uw0DTF3BsYv97JEa4PYXXqVCEvNJPwJB1cV1eX6Xyq6iKGIhMPH9k62sOc+oUdt094WCw==",
+ "license": "MIT"
+ },
"node_modules/expo-file-system": {
"version": "55.0.10",
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-55.0.10.tgz",
@@ -4614,12 +4951,12 @@
}
},
"node_modules/expo-manifests": {
- "version": "55.0.9",
- "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-55.0.9.tgz",
- "integrity": "sha512-i82j3X4hbxYDe6kxUw4u8WfvbvTj2w+9BD9WKuL0mFRy+MjvdzdyaqAjEViWCKo/alquP/hTApDTQBb3UmWhkg==",
+ "version": "55.0.11",
+ "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-55.0.11.tgz",
+ "integrity": "sha512-3+pFun4C9F/eFMVpwZgOBrBWq5sfu7rS1uxTrcg9G7jUFatNe5W6hr+M7z7aQPDf0J1afaSudUZPawx1LLf15w==",
"license": "MIT",
"dependencies": {
- "@expo/config": "~55.0.8",
+ "@expo/config": "~55.0.10",
"expo-json-utils": "~55.0.0"
},
"peerDependencies": {
@@ -4847,6 +5184,12 @@
"react-native": "*"
}
},
+ "node_modules/expo-structured-headers": {
+ "version": "55.0.0",
+ "resolved": "https://registry.npmjs.org/expo-structured-headers/-/expo-structured-headers-55.0.0.tgz",
+ "integrity": "sha512-udaNvuWb45/Sryq9FLC/blwgOChhznuqlTrUzVjC0T83pMdcmscKJX23lnNDW6hCec8p81Y3z1DIFwIyk0g/PQ==",
+ "license": "MIT"
+ },
"node_modules/expo-symbols": {
"version": "55.0.5",
"resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-55.0.5.tgz",
@@ -4883,6 +5226,36 @@
}
}
},
+ "node_modules/expo-updates": {
+ "version": "55.0.15",
+ "resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-55.0.15.tgz",
+ "integrity": "sha512-UE9Ik56trq//kNeJ/BlC5vOTYdNTvsHwhfWFYMazP1UOQK4lnX59/t0qz8Ut+3aPXZZT7+B6mnbWtic0QqN1wA==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/code-signing-certificates": "^0.0.6",
+ "@expo/plist": "^0.5.2",
+ "@expo/spawn-async": "^1.7.2",
+ "arg": "^4.1.0",
+ "chalk": "^4.1.2",
+ "debug": "^4.3.4",
+ "expo-eas-client": "~55.0.2",
+ "expo-manifests": "~55.0.11",
+ "expo-structured-headers": "~55.0.0",
+ "expo-updates-interface": "~55.1.3",
+ "getenv": "^2.0.0",
+ "glob": "^13.0.0",
+ "ignore": "^5.3.1",
+ "resolve-from": "^5.0.0"
+ },
+ "bin": {
+ "expo-updates": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/expo-updates-interface": {
"version": "55.1.3",
"resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-55.1.3.tgz",
@@ -4892,6 +5265,12 @@
"expo": "*"
}
},
+ "node_modules/expo-updates/node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "license": "MIT"
+ },
"node_modules/expo/node_modules/@expo/cli": {
"version": "55.0.15",
"resolved": "https://registry.npmjs.org/@expo/cli/-/cli-55.0.15.tgz",
diff --git a/package.json b/package.json
index edb50e5..c884e7a 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@dr.pogodin/react-native-static-server": "^0.26.0",
"@expo/vector-icons": "^15.0.2",
"@react-native-async-storage/async-storage": "2.2.0",
+ "@sentry/react-native": "~7.11.0",
"axios": "^1.13.6",
"expo": "~55.0.5",
"expo-av": "^16.0.8",
@@ -28,6 +29,7 @@
"expo-screen-orientation": "~55.0.8",
"expo-status-bar": "~55.0.4",
"expo-system-ui": "~55.0.9",
+ "expo-updates": "~55.0.15",
"pako": "^2.1.0",
"react": "19.2.0",
"react-dom": "19.2.0",
diff --git a/shims/react-native-pager-view.web.tsx b/shims/react-native-pager-view.web.tsx
new file mode 100644
index 0000000..22e990d
--- /dev/null
+++ b/shims/react-native-pager-view.web.tsx
@@ -0,0 +1,31 @@
+/**
+ * Web shim for react-native-pager-view.
+ * eas update exports for web; this replaces the native-only module
+ * with a simple View-based container that renders the first child only.
+ */
+import React from 'react';
+import { View, type ViewStyle } from 'react-native';
+
+interface PagerViewProps {
+ children: React.ReactNode;
+ style?: ViewStyle;
+ initialPage?: number;
+ scrollEnabled?: boolean;
+ onPageSelected?: (e: any) => void;
+ [key: string]: any;
+}
+
+const PagerView = React.forwardRef(
+ ({ children, style, initialPage = 0 }, ref) => {
+ const pages = React.Children.toArray(children);
+ return (
+
+ {pages[initialPage] ?? pages[0] ?? null}
+
+ );
+ },
+);
+
+PagerView.displayName = 'PagerView';
+
+export default PagerView;