Commit Graph
75 Commits
Author SHA1 Message Date
ConnorYohandGitHub 31f6ea4b25 perf(frontend): stabilize hot-path context subscriptions to fix excessive rerenders (#6373)
## Summary

The frontend was rerendering excessively across many interactions —
typing, clicking tools, opening modals, toggling the sidebar — because
**multiple compounding ref-instability cascades defeated `memo()` checks
in hot paths**. This PR fixes the cascades structurally.

Seven focused commits, low-to-high blast radius:

1. `perf(contexts): memoize BannerContext provider value`
2. `perf(contexts): memoize CommentAuthor and ActiveDocument provider
values`
3. `perf(contexts): memoize AppConfigContext provider value`
4. `perf(useToolManagement): stop spreading tool entries to keep refs
stable` — **root-cause fix**
5. `refactor(ToolPicker): hoist module-scope styles and helpers`
6. `feat(ToolWorkflowContext): add ref-stable Actions and Data subset
contexts` — additive
7. `perf(tools): migrate hot consumers to slim contexts and wrap in
memo()`

(Plus `style: apply prettier formatting` for CI.)

## What was wrong

Whenever something high-up in the tree caused a render, a chain of
unstable references propagated downward and forced every `ToolButton` to
re-execute its full body (hooks, derived computations, hook
subscriptions to other contexts). The chain:

- **4 unstable Context providers** (`Banner`, `CommentAuthor`,
`ActiveDocument`, `AppConfig`) were passing fresh `value={{ … }}`
objects on every render. Every consumer rerendered on every ancestor
render.
- **`useToolManagement.toolRegistry`** spread `{...baseTool, name,
description}` — a no-op spread that manufactured a new tool object
identity on every memo recompute.
- **The big `ToolWorkflowContext`** (25+ fields including
`state.searchQuery`) rebuilt its entire value on every
keystroke/click/toggle, forcing every `useToolWorkflow()` consumer (~36
files) to rerender.
- **`useToolNavigation`** transitively subscribed every `ToolButton` to
the full workflow context.
- **`ToolButton` & `ToolPicker`** weren't `memo()`-wrapped, so nothing
checked.
- **`ToolPanel`** passed inline `onSelect={(id) =>
handleToolSelect(...)}` — fresh ref every render, defeats child
memoization.
- **`ToolPicker`** allocated inline styles / `[]` / `toTitleCase` inside
the function body — churned `useToolSections`'s internal memo.

## Interaction matrix — what improves

The PR fixes the underlying ref-stability problem; the same fix benefits
*every* interaction that previously triggered the cascade:

| Interaction | Before | After |
|---|---|---|
| **Typing in tool search** | All visible buttons rerender per keystroke
| Only buttons whose matched-text changes rerender |
| **Clicking a tool** | All 36 `useToolWorkflow()` consumers rerender |
Only previously-selected and newly-selected buttons rerender (via
`isSelected` prop) |
| **Toggling sidebar / panel mode / reader mode** | Every tool button
rerenders | Tool components stay still (slim context doesn't see UI
state) |
| **Switching workbench / navigation** | `handleToolSelect` identity
changes → cascades through `onSelect` props | Ref-stabilized in Actions
context. Identity stable. Children's memo bails |
| **Modal/dialog open/close** | AppConfig churns → every `useAppConfig`
consumer rerenders (ToolButton reads `premiumEnabled`) | AppConfig
memoized; consumers rerender only when config changes |
| **Banner show/hide** | BannerProvider value churns → every consumer
rerenders on any ancestor render | Memoized; AppLayout rerenders only
when banner content changes |
| **Any state update high in the tree** | Compounding cascade defeats
memo everywhere | Stable subscriptions; memo bails out |

## Evidence

Per-keystroke prop instability on `ToolButton` (cleanest measurable
signal, captured via custom memo comparators logging which prop refs
differ):

| | `tool` ref diffs | `onSelect` ref diffs | `matchedSynonym` value
diffs | Total |
|---|---|---|---|---|
| Before | 18 | 18 | 6 | **42** |
| After  | 0  | 0  | 6 | **6 (all legitimate)** |

→ **86% reduction** in spurious per-keystroke prop instability. The 6
remaining matched-synonym diffs are correct (different substring
highlighted per keystroke).

Context value rebuild counts during a keystroke (verified with
instrumented `useMemo` factories): `useToolWorkflowData=0`,
`useToolWorkflowActions=0`, `AppConfigContext=0`.

The same stabilization applies to click/toggle/modal interactions — they
were all driven by the same cascading invalidations.

## Honest caveat on render-count metrics

`React.Profiler` counts and function-body execution counts in **dev
mode** came back identical before vs after (StrictMode + concurrent
rendering + Mantine internal commits dominate the numbers). The PR's
value is measured against the **prop-stability signal** above, not
Profiler counts. Production builds — where StrictMode doesn't
double-render and Mantine internals aren't constantly committing — will
show memo bail out properly.

## Risk × benefit

| # | Commit | Risk | Benefit |
|---|--------|------|---------|
| 1 | BannerContext memo |  Trivial | 🟦 Small |
| 2 | CommentAuthor + ActiveDocument memo |  Trivial | 🟦 Small |
| 3 | AppConfig memo |  Trivial | 🟦 Moderate (wide consumer base) |
| 4 | useToolManagement spread removal |  Trivial | 🟥 **High (root
cause)** |
| 5 | ToolPicker hoist |  Trivial | 🟦 Small |
| 6 | ToolWorkflowContext split | 🟧 Low-Med | 🟥 **High (foundation)** |
| 7 | Hot consumer migration + memo | 🟧 Low-Med | 🟥 **High
(actualization)** |

Commit 6 introduces an invariant: ref-stabilized callbacks in the
Actions context must only be invoked from event handlers (post-commit),
never during render. All current call sites comply.

## Test plan

- [x] `npx playwright test --project=stubbed` — 145 / 6 skipped / 0
failed before and after.
- [x] Targeted regression: `main-dashboard`, `tool-search`, `navigation`
— 11/11 passing.
- [x] CI passing on commits (one infrastructure flake on
`docker-compose-tests` — "No space left on device" — unrelated;
rerunning).
- [ ] Manual sanity check in a dev build after merge.

## What this enables

The same Actions + Data subset-context pattern can be applied to
`FileContext`, `NavigationContext`, and other big contexts. The
foundation is in place.
2026-05-19 15:56:50 +00:00
c731d5fd5d UI redesign staging (#6149)
Co-authored-by: Reece Browne <[email protected]>
Co-authored-by: James Brunton <[email protected]>
2026-05-15 15:36:50 +01:00
James BruntonandGitHub 95c39b4648 Fix missing desktop save indicator on files (#6310)
# Description of Changes
Save indicator stopped showing up after #6050, which fixed the missing
truncation on filenames, but accidentally bypassed the save indicator
component at the same time. This PR puts the component back in and makes
it support truncation so we can have both.

<img width="586" height="166" alt="image"
src="https://github.com/user-attachments/assets/529c3dcb-ee00-4a6d-ae53-ef8657204369"
/>
2026-05-05 11:19:11 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Anthony Stirling
4ab7d3b3ae build(deps): bump the mui group across 1 directory with 2 updates (#6301)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anthony Stirling <[email protected]>
2026-05-05 10:53:16 +01:00
James BruntonandGitHub cc9650e7a3 Fix any type usage in desktop/ (#6033)
# Description of Changes
Follow on from #5949, expanding any type usage ban to the `desktop/`
folder

Also gets rid of a bunch of really verbose desktop logging that I don't
think we really need anymore (or ever needed tbh, most of it doesn't
make sense) because it was using a bunch of `any` typing and wasn't
worth fixing.
2026-04-20 12:42:38 +00:00
EthanHealy01andGitHub bad92a9eae Chore/remove usage of mantine color scheme (#6108)
Remove instances of `colorScheme === "dark" ?` in the app and rely on
the theme.css' light and dark variables instead.
2026-04-17 14:29:37 +01:00
James BruntonandGitHub 8ab060a4be Prettier 2: Electric Boogaloo (#6113)
# Description of Changes
When I added Prettier formatting in #6052, my aim was to use just the
default settings in Prettier. Turns out, Prettier looks _really hard_
for any config files if it's not explicitly given one, which means that
if a developer has some sort of Prettier config file lying around on
their system, Prettier might find it and use it. Also, Prettier changes
its defaults based on stuff in `.editorconfig` without any good way of
disabling that behaviour explicitly in its config file.

To solve both of these issues, I've introduced a `.prettierrc` file
which sets Prettier's defaults explicitly, and then reformatted all our
code _again_ in Prettier's actual default settings. This should achieve
the aim of #6052 and remove the possibility for it breaking on different
dev computers.
2026-04-17 09:50:16 +00:00
James BruntonandGitHub a3e45bc182 Add frontend autoformatting and set CI to require formatted code for all languages (#6052)
# Description of Changes
Changes the strategy for autoformatting to reject PRs if they are not
formatted correctly instead of allowing them to merge and then spawning
a new PR to fix the formatting. The old strategy just caused more work
for us because we'd have to manually approve the followup PR and get it
merged, which required 2 reviewers so in practice it rarely got done and
just meant everyone's PRs ended up containing reformatting for unrelated
files, which makes code review unnecessarily difficult. If the PR's code
is not formatted correctly after this PR, a comment will be added
automatically to tell the author how to run the formatter script to fix
their code so it can go in.

This also enables autoformatting for the frontend code, using Prettier.
I've enabled it for pretty much everything in the frontend folder, other
than 3rd party files and files it doesn't make sense for. I also
excluded Markdown because it sounds likely to be more annoying to have
to autoformat the Markdown in the frontend folder but nowhere else. Open
to changing this though if people disagree.

> [!note]
> 
> Advice to reviewers: The first commit contains all of the actual logic
I've introduced (CI changes, Prettier config, etc.)
> The second commit is just the reformatting of the entire frontend
folder.
> The first commit needs proper review, the second one just give it a
spot-check that it's doing what you'd expect.
2026-04-10 17:41:19 +01:00
EthanHealy01andGitHub 11b26755a4 use clean 3 card design for landing page (#6084)
<img width="2056" height="1080" alt="Screenshot 2026-04-08 at 1 26
58 PM"
src="https://github.com/user-attachments/assets/e834988b-c3ab-4633-bf15-9fe0457d0029"
/>

<img width="2056" height="1080" alt="Screenshot 2026-04-08 at 1 27
12 PM"
src="https://github.com/user-attachments/assets/adfebd95-ca59-4de0-9336-b1e2dc1dc5fe"
/>
2026-04-09 12:38:46 +00:00
fbae819d7c Fix/desktop open with tool access (#6056)
## Description

Fixes #6029 - Additional selection in windows client no longer necessary

## Problem
When opening PDF files in the Windows desktop client using "Open with",
the file displays properly but users had to manually select it again in
the workbench before any PDF tools (merge, compress, crop, compare,
etc.) become functional.

## Root Cause
Files opened via "Open with" were added to FileContext but **not
selected** (missing `selectFiles: true`). Without selection, the file
wasn't marked as active, preventing tool access.

Additionally, `AppInitializer` was placed outside
`ToolWorkflowProvider`, causing a context error.

## Solution

### Changes:
1. **frontend/src/desktop/hooks/useAppInitialization.ts**
   - Added `{ selectFiles: true }` when calling `addFiles()`
   - Files now immediately marked as active in FileContext

2. **frontend/src/core/components/AppProviders.tsx**
   - Moved `AppInitializer` inside `ToolWorkflowProvider`
   - Ensures context availability for initialization

## Testing
- Open PDF via "Open with" on Windows
- File now immediately usable with all tools
- No manual reselection needed

## Screenshot
<img width="1920" height="1080" alt="Screenshot (3)"
src="https://github.com/user-attachments/assets/9ceacadf-eb12-42a6-86f9-bca6188bfbb9"
/>

---------

Co-authored-by: Anthony Stirling <[email protected]>
Co-authored-by: EthanHealy01 <[email protected]>
Co-authored-by: Reece Browne <[email protected]>
2026-04-08 20:39:20 +05:30
EthanHealy01andGitHub 74153b6deb Bug/connection mode fixes (#5998) 2026-04-01 15:33:46 +01:00
Matheus SaitoandGitHub 212f12a81f Added back ctrl+r as rotate if on desktop (#5982) (#5993)
Fix #5982

Behaviour of ctrl+r altered to support rotate on desktop, while the web
version continue to use refresh as default.
2026-04-01 11:48:53 +01:00
ConnorYohandGitHub 1e97a32d4b feat(desktop): gate shared signing behind self-hosted auth (#6002)
## Summary

This PR adds full desktop (Tauri) support for the shared signing feature
when connected to a self-hosted server, and fixes several bugs
discovered during that work.

### Feature gating

Shared signing, file sharing, and share links are proprietary server
features that require an authenticated self-hosted session. Previously
these were read directly from `config` with no awareness of connection
mode or auth state, meaning the UI could appear in SaaS/local mode or
when logged out.

- Introduce `useGroupSigningEnabled` and `useSharingEnabled` hooks with
core implementations (web behaviour unchanged) and desktop overrides
that require `selfhosted` mode + an active authenticated session
- Extract shared subscription logic into `useSelfHostedAuth` (connection
mode + auth state + config refetch)
- `QuickAccessBar` now derives all three flags from the hooks instead of
raw config

### Config timing fix

When a user logs in via the SetupWizard, the `jwt-available` event fires
a config fetch *before* the mode is switched to `selfhosted`. This meant
the config was fetched from the local bundled backend (port ~59567)
which has no knowledge of `storageGroupSigningEnabled`, causing the
group signing button to stay hidden until a full page refresh.
`useSelfHostedAuth` detects the mode transition and triggers a fresh
config fetch at the correct moment, after the self-hosted URL is active.

### Bug fixes

**`SignPopout.tsx`** — Manually setting `Content-Type:
multipart/form-data` on two `FormData` POST requests stripped the
auto-generated boundary, causing a `400 bad multipart` from the server.
Removed the explicit headers so Axios sets them correctly.

**`tauriHttpClient.ts`** — `response.json()` was called before
`response.ok` was checked. A plain-text error body from the server (e.g.
`"Cannot sign..."`) caused a `SyntaxError` that fell into the network
error catch block and was reported as `ERR_NETWORK`, hiding the real
failure. The fix checks `response.ok` first, reads error bodies as text,
and handles empty 200 bodies (returning `null` instead of throwing).

---

## Testing

### Prerequisites
- Desktop app running in self-hosted mode pointed at a local
Stirling-PDF instance (`http://localhost:8080`)
- The self-hosted instance has group signing and storage enabled in
settings
- At least two user accounts on the self-hosted instance

### 1. Feature gating — group signing button

| Step | Expected |
|---|---|
| Open the desktop app in **local mode** (no server configured) | Group
signing button absent from QuickAccessBar |
| Switch to self-hosted mode but **do not log in** | Group signing
button absent |
| Log in to the self-hosted server | Group signing button appears
without requiring a page refresh |
| Log out | Group signing button disappears immediately |
| Log back in | Group signing button reappears without a page refresh |

### 2. Feature gating — file sharing

Repeat the same steps above, verifying the share and share-link buttons
in the file manager follow the same visibility rules.

### 3. Create a signing session

1. Log in, open the group signing panel from QuickAccessBar
2. Select a PDF, add a participant, configure signature defaults and
submit
3. Verify the session is created successfully (no `400 bad multipart`
error)

### 4. Participant signing

1. As the invited participant, open the signing request from
QuickAccessBar
2. Upload or draw a signature and submit
3. Verify signing completes successfully (no `ERR_NETWORK` error)

### 5. Error surfacing

1. Attempt an action that the server rejects (e.g. sign a document with
an invalid certificate)
2. Verify the actual server error message is shown rather than a generic
network error
2026-03-30 14:37:45 +00:00
James BruntonandGitHub 4a6b426651 Only allow Tauri imports in the desktop app (#5995)
# Description of Changes
Adds an eslint rule to disallow importing any Tauri APIs outside the
desktop folder to help hint to developers that they should be following
the frontend architecture.

While doing this, I also discovered that you can provide a custom
message in the `no-restricted-imports` rule, which is nicer than the
comments that I'd previously added to the eslint config file to explain
why they weren't allowed:

```text
/Users/jamesbrunton/Dev/spdf1/frontend/src/core/components/shared/config/configSections/GeneralSection.tsx
  19:1  error  'src/core/contexts/PreferencesContext' import is restricted from being used by a pattern. Use @app/* imports instead of absolute src/ imports              no-restricted-imports
  20:1  error  '../../../../../core/contexts/AppConfigContext' import is restricted from being used by a pattern. Use @app/* imports instead of relative imports          no-restricted-imports
  21:1  error  '@tauri-apps/core' import is restricted from being used by a pattern. Tauri APIs are desktop-only. Review frontend/DeveloperGuide.md for structure advice  no-restricted-imports
```
2026-03-30 14:24:16 +00:00
Anthony StirlingGitHubConnorYohConnor YohEthanHealy01Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
28613caf8a fileshare (#5414)
Co-authored-by: ConnorYoh <[email protected]>
Co-authored-by: Connor Yoh <[email protected]>
Co-authored-by: EthanHealy01 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-25 11:00:40 +00:00
2e2b55e87d Desktop/remove hard requirement auth wall on desktop (#5956)
Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-03-23 19:36:48 +00:00
Reece BrowneandGitHub 41945543e0 Fix save converted files (#5971)
Fix saving converted files on tauri
2026-03-23 13:51:40 +00:00
55bcb92810 Add explicit Save As button for desktop viewer (issue #5928) (#5959)
## Description

Adds an explicit **“Save As”** button to the desktop viewer so users can
always save a copy of the current PDF to a different location, even if
the original file already has a local path.

This complements the existing smart **Save/Download** behavior:
- The existing download button continues to either save back to the
original path (when available) or prompt for a path when needed.
- The new **Save As** button always opens a save dialog to choose a
location/name for a new copy.

## Changes

- **RightRail (viewer controls)**
- Added a new **Save As** action icon in the right rail settings
section.
  - The button:
- Uses `viewerContext.exportActions.saveAsCopy()` to get the current
viewer state as a PDF.
- Calls `downloadFile` without a `localPath`, ensuring the desktop app
shows a **Save As** dialog.
- Picks the first selected file (if any) or the first active file as the
source for the filename.
- **Desktop / Web behavior**
  - In the desktop app (Tauri), clicking **Save As**:
- Opens a native save dialog so the user can choose a different folder
and filename.
- Writes a new copy without changing the existing file’s `localFilePath`
or dirty state.
- In the web app, the button behaves like a standard download of a copy
(browser-controlled save dialog / download).

## Motivation

- Users often want to apply operations on a PDF while **keeping the
original unmodified**.
- The existing smart Save behavior chooses between Save and Save As
automatically, but there was no way to explicitly request **Save As**.
- This change gives desktop users a clear, dedicated **“Save As”**
control while preserving the current Save/Download behavior.

## Notes

- No backend changes.
- No changes to the existing Save / Download button behavior.
- The new button uses existing viewer export and download utilities,
minimizing new logic.

---------

Co-authored-by: James Brunton <[email protected]>
2026-03-20 09:32:24 +00:00
ConnorYohandGitHub 214dc20c2e Hotfix-cant-run-tools-when-no-credits (#5955)
Tested:
* Can sign in on saas -> can run local tools with or without credits->
can run saas only tools (if credits) -> can't run saas only tools
without credits
* Can sign in self-hosted -> can run all tools on remote if available ->
can run local when self-hosted unavailable

Clouds show on saas tools when connected
Tools are disabled when connected to self-hosted but cannot find server.
You also get banner


#cantwaitforplaywritetests
2026-03-17 13:01:08 +00:00
7f9bbebe5b Unify creditCosts.ts files (#5952)
Co-authored-by: Anthony Stirling <[email protected]>
2026-03-16 22:05:02 +00:00
James BruntonandGitHub 971321fb19 Fix printing on Mac desktop (#5920)
# Description of Changes
Fix #5164 

As I mentioned on the bug
https://github.com/Stirling-Tools/Stirling-PDF/issues/5164#issuecomment-4045170827,
it's impossible to print on Mac currently because
`iframe.contentWindow?.print()` silently does nothing in Tauri on Mac,
but [it seems unlikely that this will be
fixed](https://github.com/tauri-apps/tauri/issues/13451#issuecomment-4048075861).

Instead, I've linked directly to the Mac `PDFKit` framework in Rust to
use its printing functionality instead of Safari's. I believe that
`PDFKit` is what `Preview.app` is using and the print UI that it
generates seems to perform identically, so this should solve the issue
on Mac. Hopefully one day the TS iframe print API will be fixed and
we'll be able to get rid of this code, or [there'll be an official Tauri
plugin for printing which we can use
instead](https://github.com/tauri-apps/plugins-workspace/issues/293).

This implementation should be entirely Mac-specific. Windows & Linux
will continue to use their TS printing (which comes from EmbedPDF)
unless we have a good reason to change them to use a native solution as
well.
2026-03-16 10:49:45 +00:00
ConnorYohandGitHub 44e036da5a Check if saas before blocking credit insufficiencies (#5929)
fixes #5926
2026-03-13 10:28:39 +00:00
0545c3f997 Cleanup-conversion-translations (#5906)
Co-authored-by: Anthony Stirling <[email protected]>
2026-03-12 20:23:13 +00:00
James BruntonandGitHub 8674765528 Add system for managing env vars (#5902)
# Description of Changes
Previously, `VITE_*` environment variables were scattered across the
codebase with hardcoded fallback values inline (e.g.
`import.meta.env.VITE_STRIPE_KEY || 'pk_live_...'`). This made it
unclear which variables
were required, what they were for, and caused real keys to be silently
used in builds where they hadn't been explicitly configured.

## What's changed

I've added `frontend/.env.example` and `frontend/.env.desktop.example`,
which declare every `VITE_*` variable the app uses, with comments
explaining each one and sensible defaults where applicable. These
are the source of truth for what's required.

I've added a setup script which runs before `npm run dev`, `build`,
`tauri-dev`, and all `tauri-build*` commands. It:
- Creates your local `.env` / `.env.desktop` from the example files on
first run, so you don't need to do anything manually
- Errors if you're missing keys that the example defines (e.g. after
pulling changes that added a new variable). These can either be
manually-set env vars, or in your `.env` file (env vars take precedence
over `.env` file vars when running)
- Warns if you have `VITE_*` variables set in your environment that
aren't listed in any example file

I've removed all `|| 'hardcoded-value'` defaults from source files
because they are not necessary in this system, as all variables must be
explicitly set (they can be set to `VITE_ENV_VAR=`, just as long as the
variable actually exists). I think this system will make it really
obvious exactly what you need to set and what's actually running in the
code.

I've added a test that checks that every `import.meta.env.VITE_*`
reference found in source is present in at least one example file, so
new variables can't be added without being documented.

## For contributors

New contributors shouldn't need to do anything - `npm run dev` will
create your `.env` automatically.

If you already have a `.env` file in the `frontend/` folder, you may
well need to update it to make the system happy. Here's an example
output from running `npm run dev` with an old `.env` file:

```
$ npm run dev

> [email protected] dev
> npm run prep && vite


> [email protected] prep
> tsx scripts/setup-env.ts && npm run generate-icons

setup-env: see frontend/README.md#environment-variables for documentation
setup-env: .env is missing keys from config/.env.example:
  VITE_GOOGLE_DRIVE_CLIENT_ID
  VITE_GOOGLE_DRIVE_API_KEY
  VITE_GOOGLE_DRIVE_APP_ID
  VITE_PUBLIC_POSTHOG_KEY
  VITE_PUBLIC_POSTHOG_HOST
  Add them manually or delete your local file to re-copy from the example.
setup-env: the following VITE_ vars are set but not listed in any example file:
  VITE_DEV_BYPASS_AUTH
  Add them to config/.env.example or config/.env.desktop.example if they are required.
```

If you add a new `VITE_*` variable to the codebase, add it to the
appropriate `frontend/config/.env.example` file or the test will fail.
2026-03-12 13:03:44 +00:00
ConnorYohandGitHub d5d03b9ada Manage state of price-lookup calls (#5915)
Now calls stripe-price-lookup once when prices are required rather then
bombarding on every rerender
2026-03-11 13:53:49 +00:00
James BruntonandGitHub fa8c52b2be Add SaaS frontend code (#5879)
# Description of Changes
Adds the code for the SaaS frontend as proprietary code to the OSS repo.
This version of the code is adapted from 22/1/2026, which was the last
SaaS version based on the 'V2' design. This will move us closer to being
able to have the OSS products understand whether the user has a SaaS
account, and provide the correct UI in those cases.
2026-03-11 11:53:54 +00:00
ConnorYohandGitHub 8bc37bf5ae Desktop: Fallback to local backend if self-hosted server is offline (#5880)
* Adds a fallback mechanism so the desktop app routes tool operations to
the local bundled backend when the user's self-hosted Stirling-PDF
server goes offline, and disables tools in the UI that aren't supported
locally.

* `selfHostedServerMonitor.ts` independently polls the self-hosted
server every 15s and exposes which tool endpoints are unavailable when
it goes offline
* `operationRouter.ts` intercepts operations destined for the
self-hosted server and reroutes them to the local bundled backend when
the monitor reports it offline
* `useSelfHostedToolAvailability.ts` feeds the offline tool set into
useToolManagement, disabling affected tools in the UI with a
selfHostedOffline reason and banner warning

- `SelfHostedOfflineBanner `is a dismissable (session-only) gray bar
shown at the top of the UI when in self-hosted mode and the server goes
offline. It shows:
2026-03-10 10:04:56 +00:00
Anthony StirlingandGitHub 879ffc066f tauri notifications (#5875) 2026-03-05 18:30:20 +00:00
ConnorYohandGitHub c4c43593e6 fallback for /api/v1/config/endpoints-availability (#5842) 2026-03-02 22:03:23 +00:00
Reece BrowneandGitHub 213f136882 lint (#5802) 2026-02-25 18:20:24 +00:00
James BruntonandGitHub c9dafc85fd Switch to use ESLint 10 (#5794) 2026-02-25 14:30:40 +00:00
5c39acecd8 Desktop connection SaaS: config, billing, team support (#5768)
Co-authored-by: James Brunton <[email protected]>
Co-authored-by: James Brunton <[email protected]>
2026-02-25 14:13:07 +00:00
eab84a13d0 Change to use dpdm for circular import scanning (#5788)
Co-authored-by: Anthony Stirling <[email protected]>
2026-02-24 23:05:23 +00:00
James BruntonandGitHub 73213901d1 Fix cookie consent reappearing on desktop builds (#5780)
# Description of Changes
Fix #5779. Cookie consent persistance doesn't work on desktop (on Mac at
least, not sure about Windows) because of permission differences with
Tauri. We are allowed to store things in local storage fine, so this
switches the cookie consent module to store in local storage for
desktop, and leaves it alone for web, where it already worked correctly.
2026-02-23 20:53:31 +00:00
Anthony StirlingandGitHub 9a10fcb590 authclient (#5761)
# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## 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.
2026-02-20 12:08:47 +00:00
Anthony StirlingandGitHub ae9d29abf0 large query reduction (#5754)
# Description of Changes

Reduce endpoint-availability call so that an empty param to it returns
all endpoints to avoid pointlessly large http headers


Before:
GET
/api/v1/config/endpoints-availability?endpoints=compress-pdf%2Crotate-pdf%2Cmerge-pdfs%2Csplit-pages%2Cocr-pdf
  for all 74 tools

  After:
  GET /api/v1/config/endpoints-availability
---

## 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.
2026-02-18 10:52:59 +00:00
Anthony StirlingandGitHub ddf93d2b1a fixes for desktop SSO (#5751)
# Description of Changes



Race condition: The browser was opened before the deep-link listener was
registered. On slow first launches the OAuth
callback could arrive before the listener was ready. Fixed by
registering the listener first, then opening the browser
   inside .then() once the listener is confirmed active.

Double-handling: Both SetupWizard and
authService.waitForDeepLinkCompletion processed the same
sso/sso-selfhosted deep
links, calling completeSelfHostedSession and onComplete() independently.
Fixed by moving all SSO completion into
  authService and having SetupWizard defer to it.

Hardening: Removing SetupWizard's handler entirely left no fallback if
the webview reloads while the auth listener's
Promise is in flight. A selfHostedDeepLinkFlowActive flag tracks whether
authService has an active listener.
SetupWizard now acts as a fallback only when the flag is false (i.e.
after a JS context reset), preventing duplicate
  handling in the normal path while preserving resilience on reload.
---

## 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.
2026-02-18 10:46:15 +00:00
Anthony StirlingandGitHub 558c75a2b1 JWT enhancements for desktop (#5742)
# Description of Changes

This is temporary solution which will be enhanced in future

---

## 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.
2026-02-16 21:57:42 +00:00
b8ce4e47c1 Preserve local paths for desktop saves (#5543)
# Summary

- Adds desktop file tracking: local paths are preserved and save buttons
now work as expcted (doing Save/Save As as appropriate)
- Adds logic to track whether files are 'dirty' (they've been modified
by some tool, and not saved to disk yet).
- Improves file state UX (dirty vs saved) and close warnings
- Web behaviour should be unaffected by these changes

## Indicators
Files now have indicators in desktop mode to tell you their state.

### File up-to-date with disk

<img width="318" height="393" alt="image"
src="https://github.com/user-attachments/assets/06325f9a-afd7-4c2f-8a5b-6d11e3093115"
/>

### File modified by a tool but not saved to disk yet

<img width="357" height="385" alt="image"
src="https://github.com/user-attachments/assets/1a7716d9-c6f7-4d13-be0d-c1de6493954b"
/>

### File not tracked on disk

<img width="312" height="379" alt="image"
src="https://github.com/user-attachments/assets/9cffe300-bd9a-4e19-97c7-9b98bebefacc"
/>

# Limitations
- It's a bit weird that we still have files stored in indexeddb in the
app, which are still loadable. We might want to change this behaviour in
the future
- Viewer's Save doesn't persist to disk. I've left that out here because
it'd need a lot of testing to make sure the logic's right with making
sure you can leave the Viewer with applying the changes to the PDF
_without_ saving to disk
- There's no current way to do Save As on a file that has already been
persisted to disk - it's only ever Save. Similarly, there's no way to
duplicate a file.

---------

Co-authored-by: James Brunton <[email protected]>
Co-authored-by: James Brunton <[email protected]>
2026-02-13 23:15:28 +00:00
f9d2f36ab7 Bug fixing and debugs (#5704)
Co-authored-by: ConnorYoh <[email protected]>
2026-02-11 18:43:29 +00:00
Anthony StirlingGitHubstirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
00a9174939 SSO styling changes (#5671)
# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## 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.

---------

Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2026-02-06 22:00:42 +00:00
Anthony StirlingandGitHub ba72a2a623 Headless windows installer (#5664) 2026-02-06 18:06:01 +00:00
LudyandGitHub dc6daaad0d feat(desktop): show and reuse last used server URL in Setup Wizard (#5659)
# Description of Changes

This pull request enhances the server selection experience in the setup
wizard by remembering and displaying the last used server URL. Users can
now quickly reuse their previous server connection, improving usability
and reducing repetitive input.

**Server selection improvements:**

* The last used server URL is now stored in `localStorage` and
automatically displayed as a quick-select button in the
`ServerSelection` component, allowing users to easily reconnect to their
previous server.
[[1]](diffhunk://#diff-3a9a7d483f3f7789dbe410067f4401aea5898ad6692755c63e7787585b923151R19-R25)
[[2]](diffhunk://#diff-3a9a7d483f3f7789dbe410067f4401aea5898ad6692755c63e7787585b923151R212-R223)
[[3]](diffhunk://#diff-3a9a7d483f3f7789dbe410067f4401aea5898ad6692755c63e7787585b923151R38)
* A new translation string `useLast` was added to
`frontend/public/locales/en-GB/translation.toml` to support the "Last
used server" button label.

<img width="1282" height="832" alt="image"
src="https://github.com/user-attachments/assets/6f8a6d3a-9f6b-4bcb-9470-da3ad50a4409"
/>

---

## 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.
2026-02-06 10:44:42 +00:00
2ae413c5ea Stop attempting to refresh Spring tokens in desktop (#5610)
# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## 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: James Brunton <[email protected]>
2026-01-31 20:28:59 +00:00
James BruntonandGitHub 1cc562a6b1 Stop type checking TypeScript files that won't be run (#5607)
# Description of Changes
This PR fixes false-positive TypeScript errors in our layered build
setup (core → proprietary → desktop) by ensuring each build’s typecheck
only evaluates files that are actually part of that build’s reachable
module graph. This prevents overridden core implementations from being
typechecked in higher-layer builds where they are effectively
unreachable due to alias-based overrides.

## Background

We maintain multiple build targets from a layered source tree:

- core: open source baseline
- proprietary: core + proprietary additions/overrides
- desktop: proprietary + desktop-specific additions/overrides

We implement overrides via paths/aliases such that placing a file in a
higher layer at the same relative path supersedes the lower-layer file
at runtime.

For safety, we run TypeScript typechecking independently per build
target to ensure all builds remain valid.

## Problem

Our existing tsconfig setup often typechecked files that are not
actually reachable in a given build. Specifically:

- When a file in core is overridden by a file in proprietary or desktop,
the overridden core file can still be included in the TypeScript Program
for the higher-layer build (typically due to broad include globs).
- This produces false-positive type errors in higher-layer typecheck
runs, even though those core files are effectively unreachable in the
build.

This created friction and noise, and meant we had to make unnecessary
changes to `core` to make the other builds happy, reducing type safety
in the process.

## Solution

This PR adjusts the tsconfig strategy so each build target's typecheck
is driven by reachable entrypoints rather than blanket inclusion of all
layer source trees. Concretely:

- Each build’s tsconfig now includes only:
- that build’s entrypoints and layer sources that are intended to be
compiled for the target
  - any shared/top-level sources required by the target
- Lower layers (e.g., core) are not globally included in higher-layer
builds; they are instead pulled in through module resolution only when
actually referenced (with paths ordering ensuring the correct override
wins).
- This means that we still check all the files that will actually be run
with whatever the overridden logic is, but avoid wasting time and
introducing false-positives by not checking files which have been
overridden.

## Notes
Unfortunately, the config we use for the type checking can't be the same
as the one we use for Vite in this strategy. Vite needs to know about
the entire source tree, so it can't only include the subfolders because
it causes build errors. Because of this, I've duplicated the existing
(valid) tsconfig files and use them for Vite. This is a little clunky
but it does the job. Some day hopefully I'll come back to it and be able
to figure out a nicer way to do it, but for now at least, this solves
the type checking issues without impacting the runtime builds.

Also, I noticed that `@desktop` is defined as an alias, which was
presumably missed when I was removing the self-aliases from the files. I
don't see why you'd ever need to have a desktop file reference
`@desktop` to say "import this but make it impossible for something else
to override the import". I've removed the `@desktop` alias in this PR
while I was in there.
2026-01-30 15:27:35 +00:00
Anthony StirlingandGitHub f3cf747cfe possible login fixes (#5444)
# Description of Changes

Disable TLS checks and various cert checks to allow all sorts of
selfhost machines to be connected via tauri app

Version bump

Crop tool correctly shows ghostscript as optional so its not disabled on
java only installations

---

## 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.
2026-01-28 23:57:43 +00:00
43d4b46b31 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 <[email protected]>
2026-01-28 10:35:59 +00:00
0b86dd79d3 feat(security): add TOTP-based multi-factor authentication with backend and UI support (#5417)
# Description of Changes

This pull request introduces several improvements and new features
across the authentication and admin data APIs, with a particular focus
on multi-factor authentication (MFA) support and better handling of user
settings. The changes include integrating MFA status into account data
responses, masking sensitive user settings in admin views, and
refactoring code to use more robust user creation methods. Additionally,
there are minor code cleanups and consistency improvements.

### Multi-factor Authentication (MFA) Integration

* Added `mfaEnabled` and `mfaRequired` fields to the `AccountData`
response, populated using the new `MfaService`, to provide clients with
MFA status information for users.
[[1]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1R430-R431)
[[2]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1R72)
[[3]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1L83-R86)
[[4]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1R98)
[[5]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1R574-R575)

### User Settings Handling and Security

* Admin settings API now returns user settings for each user, with the
`mfaSecret` field masked to protect sensitive information. This is
achieved by fetching settings via `findByIdWithSettings` and
copying/masking the relevant field before returning.
[[1]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1R252-R259)
[[2]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1L302-R322)
[[3]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1R378)
[[4]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1R563)

### Refactoring and Code Consistency

* Refactored user creation in `InitialSecuritySetup` to use the
`SaveUserRequest` builder and `saveUserCore` for better maintainability
and clarity, replacing direct calls to `saveUser`.
[[1]](diffhunk://#diff-0c7960a6283a07c4905ac9785b2820b412574c9f86918ada30caba0356d34850R22)
[[2]](diffhunk://#diff-0c7960a6283a07c4905ac9785b2820b412574c9f86918ada30caba0356d34850L116-R124)
[[3]](diffhunk://#diff-0c7960a6283a07c4905ac9785b2820b412574c9f86918ada30caba0356d34850L130-R144)
[[4]](diffhunk://#diff-0c7960a6283a07c4905ac9785b2820b412574c9f86918ada30caba0356d34850L140-R160)
* Standardized checks for internal team membership by comparing with
`TeamService.INTERNAL_TEAM_NAME` on the left side for consistency.
[[1]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1L267-R273)
[[2]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1L332-R351)
[[3]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1L421-R443)
[[4]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1L449-R471)
[[5]](diffhunk://#diff-2ead183708656f2c6894b28457623820c83b1ed4b0814533caa0e8f0dd6fbcd1L462-R485)

### API and DTO Changes

* Changed the login API to accept `UsernameAndPassMfa` instead of
`UsernameAndPass`, paving the way for MFA code support in authentication
requests.
[[1]](diffhunk://#diff-9ca4f9246abe79368552264e2e18d7ed039e084c70c0794eb02cfd1b75fbd8a8L30-R41)
[[2]](diffhunk://#diff-9ca4f9246abe79368552264e2e18d7ed039e084c70c0794eb02cfd1b75fbd8a8L61-R71)
* Updated import statements and controller dependencies to include new
DTOs and services related to MFA.
[[1]](diffhunk://#diff-9ca4f9246abe79368552264e2e18d7ed039e084c70c0794eb02cfd1b75fbd8a8L14-R19)
[[2]](diffhunk://#diff-9ca4f9246abe79368552264e2e18d7ed039e084c70c0794eb02cfd1b75fbd8a8R56-R57)

These updates improve security, prepare the system for MFA rollout, and
make admin and authentication APIs more robust and informative.

---

## 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 <[email protected]>
2026-01-23 21:34:57 +00:00
a3b2a9b3e3 feat(frontend): enhance icon detection and update config navigation icon (#5524)
# Description of Changes

### What was changed
- Extended the `generate-icons.js` script to detect additional icon
usage patterns:
  - `<LocalIcon icon='...' />` with single-quoted icon names
- Icon definitions inside configuration objects (`icon: '...'` or `icon:
"..."`)
- Updated the configuration navigation icon for the *Connection Mode*
section from `cloud-rounded` to `desktop-cloud-rounded` in both
hook-based and static section definitions.

### Why the change was made
- The icon generation script previously missed icons referenced via
`LocalIcon` with single quotes and icons defined in config objects,
which could lead to missing assets in builds.
- The navigation icon update aligns the UI with the intended
desktop-specific icon semantics.


---

## 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 <[email protected]>
2026-01-22 19:37:37 +00:00
Anthony StirlingandGitHub d2677e64dd OCR fix and Mobile QR changes (#5433)
# Description of Changes
## OCR / Tesseract path handling

Makes tessDataPath resolution deterministic with priority: config >
TESSDATA_PREFIX env > default.
Updates language discovery to use runtimePathConfig.getTessDataPath()
instead of raw config value.
Ensure default OCR dir is debian based not alpine

## Mobile scanner: feature gating + new conversion settings
Adds system.mobileScannerSettings (convert-to-PDF + resolution + page
format + stretch) exposed via backend config and configurable in the
proprietary admin UI.
Enforces enableMobileScanner on the MobileScannerController endpoints
(403 when disabled).
Frontend mobile upload flow can now optionally convert received images
to PDF (pdf-lib + canvas).

## Desktop/Tauri connectivity work
Expands tauri-plugin-http permissions and enables dangerous-settings.
Adds a very comprehensive multi-stage server connection diagnostic
routine (with lots of logging).


<img width="688" height="475" alt="image"
src="https://github.com/user-attachments/assets/6f9c1aec-58c7-449b-96b0-52f25430d741"
/>


---

## 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.
2026-01-12 11:18:37 +00:00