deps(frontend, tauri): update Tauri, Rust crates, and frontend dependencies (#5569)

# Description of Changes

This pull request primarily updates dependencies for both the frontend
JavaScript and Rust (Tauri) codebases, and refactors the
`MobileUploadModal` component to consistently use a centralized API
client for backend communication. The refactor improves code
consistency, error handling, and logging in the file upload workflow.

**Dependency updates**

* Updated several Tauri-related dependencies in both
`frontend/package.json` and `frontend/src-tauri/Cargo.toml` to their
latest versions, including `@tauri-apps/api`, `@tauri-apps/plugin-fs`,
`@tauri-apps/plugin-http`, `@tauri-apps/plugin-shell`, and associated
Rust crates. This ensures better compatibility, security, and access to
new features.
[[1]](diffhunk://#diff-da6498268e99511d9ba0df3c13e439d10556a812881c9d03955b2ef7c6c1c655L46-R49)
[[2]](diffhunk://#diff-da6498268e99511d9ba0df3c13e439d10556a812881c9d03955b2ef7c6c1c655L129-R132)
[[3]](diffhunk://#diff-91e702206f8c6459b43ae72dbd6abfed8104de661dd239d13956985210f67fd0L21-R35)
* Updated `@iconify-json/material-symbols` and `@tauri-apps/cli` in
`package.json` for improved icon support and build tooling.

**Refactor: API client usage in `MobileUploadModal`**

* Replaced all direct `fetch` calls in `MobileUploadModal.tsx` with the
centralized `apiClient`, standardizing backend requests and improving
maintainability.
[[1]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aR13)
[[2]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL84-R98)
[[3]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL116-R122)
[[4]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL130-R138)
[[5]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL160-R177)
[[6]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL187-R207)
* Improved error handling, status checks, and logging throughout the
upload and session management flow, making debugging easier and the user
experience more robust.
[[1]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL84-R98)
[[2]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL130-R138)
[[3]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL148-R153)
[[4]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL160-R177)
[[5]](diffhunk://#diff-fafb4b340343062aba7b763dea5e6e13e0e330ab2ac7dfd04a2032ba79620c8aL187-R207)

**Session cleanup improvements**

* Ensured that mobile scanner sessions are reliably cleaned up both when
the modal closes and when the component unmounts, using the `apiClient`
and React's effect cleanup mechanism.

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Ludy 2026-01-28 11:35:59 +01:00 committed by GitHub
parent eee17d4d19
commit 43d4b46b31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1523 additions and 1247 deletions

File diff suppressed because it is too large Load Diff

View File

@ -43,13 +43,13 @@
"@supabase/supabase-js": "^2.47.13",
"@tailwindcss/postcss": "^4.1.13",
"@tanstack/react-virtual": "^3.13.12",
"@tauri-apps/api": "^2.5.0",
"@tauri-apps/plugin-fs": "^2.4.0",
"@tauri-apps/plugin-http": "^2.5.4",
"@tauri-apps/plugin-shell": "^2.3.3",
"@tauri-apps/api": "^2.9.1",
"@tauri-apps/plugin-fs": "^2.4.5",
"@tauri-apps/plugin-http": "^2.5.6",
"@tauri-apps/plugin-shell": "^2.3.4",
"autoprefixer": "^10.4.21",
"axios": "^1.12.2",
"globals": "^17.0.0",
"axios": "^1.13.2",
"globals": "^17.1.0",
"i18next": "^25.5.2",
"i18next-browser-languagedetector": "^8.2.0",
"jszip": "^3.10.1",
@ -58,7 +58,7 @@
"pdfjs-dist": "^5.4.149",
"peerjs": "^1.5.5",
"posthog-js": "^1.268.0",
"qrcode.react": "^4.1.0",
"qrcode.react": "^4.2.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-i18next": "^15.7.3",
@ -126,10 +126,10 @@
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@iconify-json/material-symbols": "^1.2.48",
"@iconify/utils": "^3.0.2",
"@iconify-json/material-symbols": "^1.2.53",
"@iconify/utils": "^3.1.0",
"@playwright/test": "^1.55.0",
"@tauri-apps/cli": "^2.5.0",
"@tauri-apps/cli": "^2.9.6",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.8.0",
"@testing-library/react": "^16.3.0",

File diff suppressed because it is too large Load Diff

View File

@ -18,21 +18,21 @@ name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.2.0", features = [] }
tauri-build = { version = "2.5.3", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
log = "0.4"
tauri = { version = "2.9.0", features = [ "devtools"] }
tauri-plugin-log = "2.0.0-rc"
tauri-plugin-shell = "2.1.0"
tauri-plugin-fs = "2.4.4"
tauri-plugin-http = { version = "2.4.4", features = ["dangerous-settings"] }
tauri-plugin-single-instance = { version = "2.3.6", features = ["deep-link"] }
tauri-plugin-store = "2.1.0"
tauri-plugin-opener = "2.0.0"
tauri-plugin-deep-link = "2.4.5"
tauri-plugin-log = "2.8.0"
tauri-plugin-shell = "2.3.4"
tauri-plugin-fs = "2.4.5"
tauri-plugin-http = { version = "2.5.6", features = ["dangerous-settings"] }
tauri-plugin-single-instance = { version = "2.3.7", features = ["deep-link"] }
tauri-plugin-store = "2.4.2"
tauri-plugin-opener = "2.5.3"
tauri-plugin-deep-link = "2.4.6"
keyring = { version = "3.6.1", features = ["apple-native", "windows-native"] }
tokio = { version = "1.0", features = ["time", "sync"] }
reqwest = { version = "0.11", features = ["json"] }

View File

@ -10,6 +10,7 @@ import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
import { Z_INDEX_OVER_FILE_MANAGER_MODAL } from '@app/styles/zIndex';
import { withBasePath } from '@app/constants/app';
import { convertImageToPdf, isImageFile } from '@app/utils/imageToPdfUtils';
import apiClient from '@app/services/apiClient';
interface MobileUploadModalProps {
opened: boolean;
@ -75,26 +76,27 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
// Use configured frontendUrl if set, otherwise use current origin
// Combine with base path and mobile-scanner route
const frontendUrl = config?.frontendUrl || window.location.origin;
const baseUrl = localStorage.getItem('server_url') || '';
const frontendUrl = baseUrl || config?.frontendUrl || window.location.origin;
const mobileUrl = `${frontendUrl}${withBasePath('/mobile-scanner')}?session=${sessionId}`;
// Create session on backend
const createSession = useCallback(async (newSessionId: string) => {
try {
const response = await fetch(`/api/v1/mobile-scanner/create-session/${newSessionId}`, {
method: 'POST'
const response = await apiClient.post<SessionInfo>(`/api/v1/mobile-scanner/create-session/${newSessionId}`, undefined, {
responseType: 'json',
});
if (!response.ok) {
if (!response.status || response.status !== 200) {
throw new Error('Failed to create session');
}
const data = await response.json();
const data = response.data;
setSessionInfo(data);
setError(null);
console.log('Session created:', data);
console.log('[MobileUploadModal] Session created:', data);
} catch (err) {
console.error('Failed to create session:', err);
console.error('[MobileUploadModal] Failed to create session:', err);
setError(t('mobileUpload.sessionCreateError', 'Failed to create session'));
}
}, [t]);
@ -113,12 +115,12 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
if (!opened) return;
try {
const response = await fetch(`/api/v1/mobile-scanner/files/${sessionId}`);
if (!response.ok) {
const response = await apiClient.get(`/api/v1/mobile-scanner/files/${sessionId}`);
if (!response.status || response.status !== 200) {
throw new Error('Failed to check for files');
}
const data = await response.json();
const data = response.data;
const files = data.files || [];
// Download only files we haven't processed yet
@ -127,12 +129,14 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
if (newFiles.length > 0) {
for (const fileMetadata of newFiles) {
try {
const downloadResponse = await fetch(
`/api/v1/mobile-scanner/download/${sessionId}/${fileMetadata.filename}`
const downloadResponse = await apiClient.get(
`/api/v1/mobile-scanner/download/${sessionId}/${fileMetadata.filename}`, {
responseType: 'blob',
}
);
if (downloadResponse.ok) {
const blob = await downloadResponse.blob();
if (downloadResponse.status === 200) {
const blob = downloadResponse.data;
let file = new File([blob], fileMetadata.filename, {
type: fileMetadata.contentType || 'image/jpeg'
});
@ -145,9 +149,9 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
pageFormat: config?.mobileScannerPageFormat as 'keep' | 'A4' | 'letter' | undefined,
stretchToFit: config?.mobileScannerStretchToFit,
});
console.log('Converted image to PDF:', file.name);
console.log('[MobileUploadModal] Converted image to PDF:', file.name);
} catch (convertError) {
console.warn('Failed to convert image to PDF, using original file:', convertError);
console.warn('[MobileUploadModal] Failed to convert image to PDF, using original file:', convertError);
// Continue with original image file if conversion fails
}
}
@ -157,21 +161,21 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
onFilesReceived([file]);
}
} catch (err) {
console.error('Failed to download file:', fileMetadata.filename, err);
console.error('[MobileUploadModal] Failed to download file:', fileMetadata.filename, err);
}
}
// Delete the entire session immediately after downloading all files
// This ensures files are only on server for ~1 second
try {
await fetch(`/api/v1/mobile-scanner/session/${sessionId}`, { method: 'DELETE' });
console.log('Session cleaned up after file download');
await apiClient.delete(`/api/v1/mobile-scanner/session/${sessionId}`);
console.log('[MobileUploadModal] Session cleaned up after file download');
} catch (cleanupErr) {
console.warn('Failed to cleanup session after download:', cleanupErr);
console.warn('[MobileUploadModal] Failed to cleanup session after download:', cleanupErr);
}
}
} catch (err) {
console.error('Error polling for files:', err);
console.error('[MobileUploadModal] Error polling for files:', err);
setError(t('mobileUpload.pollingError', 'Error checking for files'));
}
}, [opened, sessionId, onFilesReceived, t]);
@ -184,14 +188,24 @@ export default function MobileUploadModal({ opened, onClose, onFilesReceived }:
setError(null);
setShowExpiryWarning(false);
processedFiles.current.clear();
} else {
// Clean up session when modal closes
if (sessionId) {
fetch(`/api/v1/mobile-scanner/session/${sessionId}`, { method: 'DELETE' })
.catch(err => console.warn('Failed to cleanup session on close:', err));
}
}
}, [opened]); // Only run when opened changes
}, [opened, sessionId]); // Only run when opened changes
useEffect(() => {
if (!opened) return;
createSession(sessionId);
setFilesReceived(0);
setError(null);
setShowExpiryWarning(false);
processedFiles.current.clear();
return () => {
console.log('Cleaning up session on unmount/close:', sessionId);
apiClient.delete(`/api/v1/mobile-scanner/session/${sessionId}`)
.catch(err => console.warn('[MobileUploadModal] Cleanup failed:', err));
};
}, [opened, sessionId, createSession]);
// Start polling for files when modal opens
useEffect(() => {

View File

@ -45,6 +45,8 @@ export function setupApiInterceptors(client: AxiosInstance): void {
extendedConfig.url = `${baseUrl}${extendedConfig.url}`;
}
localStorage.setItem('server_url', baseUrl);
// Debug logging
console.debug(`[apiClientSetup] Request to: ${extendedConfig.url}`);