mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
f201aa59152b7e79f2d74a633ea160580b3e6eef
5438
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f201aa5915 |
feat(account-link): Phase 2 — instance metering + daily usage sync (#6839)
## Account-link Phase 2: metering + daily usage sync Phase 1 (already on main) let a self-hosted instance link a SaaS account and blocked billable work when it was over its limit. It blocked, but it never actually charged anything. This PR adds the metering + billing half. **It's off by default.** Everything sits behind `stirling.billing.account-link.metering.enabled`, on top of the existing `stirling.billing.account-link.enabled` master flag. Both have to be on for any of it to run, so it can't touch production. The billing model isn't going live yet — this is a dark merge. ### How it works 1. The instance classifies each billable request (API / AI / Automation — manual PDF editing stays free) and counts it locally into a per-period counter. 2. Once a day it reports its running totals to SaaS. 3. SaaS bills only the delta since the last report, reusing the existing charge path (free grant + wallet ledger + Stripe meter). No new money logic. 4. The portal shows current usage (synced spend plus anything not reported yet), and when you subscribe it now reflects the new plan right away instead of waiting for a cache to expire. ### What's worth a reviewer's eyes - **It can't double-charge.** SaaS only ever bills the delta, refuses a counter that goes backwards, dedups repeat/late reports on a monotonic sequence number, and takes a row lock so a duplicate delivery can't charge twice. - **The cap is enforced at the instance gate**, not in the charge path (same as the in-cloud flow). A $0 cap blocks all metered work. - Page counts use jpdfium so the instance and the cloud agree on the number that gets billed. - New SaaS surface: `POST /api/v1/instance/sync`, migrations V25 (`payg_instance_usage`) and V26 (allow the `LINKED_INSTANCE` job source), and a small `POST /api/v1/payg/wallet/refresh` the portal calls after checkout. ### Companion PR Stirling-PDF-SaaS #314 (on `v3`): the checkout edge function so the embedded Stripe flow finishes in-page instead of reloading, plus a `Deno.serve` migration so the edge functions actually deploy. ### Testing Java unit tests (proprietary + saas), portal vitest, and the SaaS edge-function tests all pass. Branch is merged up to date with main. ### Not done yet (doesn't block this merge — only matters once both flags are on) - V25 Supabase twin in the SaaS repo. - Same in-page checkout fix for the editor's upgrade modal. - A flags-on smoke test in staging (one real sync round-trip). --------- Co-authored-by: James Brunton <james@stirlingpdf.com> |
||
|
|
b69b787d63 |
Fix Playwright tests in Firefox and Safari (#6868)
# Description of Changes Playwright tests currently fail in Firefox and Safari because of inconsistent behaviour across the browsers. This is causing the nightlies to fail every night. This PR fixes the test behaviour to work consistently across browsers (most of the issues were to do with the tests opening the file picker, which was being automatically suppressed in Chromium, but not the other browsers). |
||
|
|
e630d6697b |
Fix tooltip positioning on Add Page Numbers (#6885)
# Description of Changes ## Before <img width="483" height="227" alt="image" src="https://github.com/user-attachments/assets/4bf86eec-a9cc-4f63-84f0-4eb2bd535bab" /> ## After <img width="732" height="235" alt="image" src="https://github.com/user-attachments/assets/101d2ea4-36e8-4e8f-990a-d72b33fa0ac2" /> |
||
|
|
a15e8227b4 |
fix(ci): upload Playwright reports from the correct frontend directory (#6859)
# Description of Changes
This change fixes the artifact upload path used by the Playwright E2E
workflows after the frontend directory structure was updated.
### What was changed
- Updated the Playwright report artifact path from:
- `frontend/editor/playwright-report/`
- to `frontend/playwright-report/`
- Applied the fix to:
- `build-enterprise.yml`
- `e2e-stubbed.yml`
- `nightly.yml`
- Renamed the nightly Playwright artifact from:
- `playwright-nightly-${{ github.run_id }}`
- to `playwright-report-nightly-${{ github.run_id }}`
for consistency with the other workflows.
### Why the change was made
The workflows attempted to upload artifacts from a directory that no
longer exists, causing GitHub Actions to report:
> No files were found with the provided path:
`frontend/editor/playwright-report/`
Updating the upload path ensures Playwright reports are successfully
collected and available for debugging failed E2E runs.
---
## 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/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 run `task check` to verify linters, typechecks, and tests
pass
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing)
for more details.
|
||
|
|
12563050a6 |
Generate frontend license report on push (#6877)
# Description of Changes `app/allowed-licenses.json` has been modified in preparation for when "org.springframework.boot" is upgraded to version "4.0.7". --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
1abd23cf94 |
fix(frontend): respect analytics config before initializing PostHog (#6812)
# Description of Changes Please provide a summary of the changes, including: - What was changed - Moved PostHog startup out of `index.tsx` and into a config-aware initializer inside `AppProviders`. - Added a dedicated `usePosthogTracking` hook that only initializes PostHog when `enableAnalytics` is explicitly `true` and `enablePosthog` is not disabled. - Kept cookie-consent handling in the same flow so consent is applied only after PostHog is actually initialized. - Removed the unconditional `PostHogProvider` and `posthog.init(...)` bootstrap from the app entrypoint. - Added targeted frontend tests covering analytics-disabled and analytics-enabled startup behavior. - Why the change was made - The previous frontend bootstrap initialized PostHog before app config was loaded, so disabling analytics in the UI or via environment settings did not prevent PostHog network activity. - This change makes analytics behavior follow the server-provided config instead of always connecting on page load. Closes #6358 --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/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) - [x] I have performed a self-review of my own code - [x] 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) - [x] I have run `task check` to verify linters, typechecks, and tests pass - [x] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
11ba3814e5 |
Restructure Portal code to be inside Editor (#6857)
# Description of Changes We don't have any strong reasons to keep the Portal as a separate Vite app, and it needs access to so many things from the Editor that it no longer makes sense to keep them separate. This PR moves the Portal code to have direct access to the Editor code and gets rid of the shared folder. |
||
|
|
675afe9b71 |
Disable update check and notification in SaaS mode (#6863)
# Description of Changes In SaaS mode the self-hosted "Update Available" notification could still appear and the update-check code (external call to `supabase.stirling.com/functions/v1/updates`) still ran, even though the cloud owns app versioning. The web `UpdateStartupPopup` was already SaaS-gated via a null override, but two other paths were not: - **Desktop app in SaaS connection mode** - `useDesktopUpdatePopup()` ran its startup check and rendered the `UpdateModal` regardless of connection mode, so a self-hosted update popup appeared while connected to SaaS. - **Settings → General** - the core `GeneralSection` fired `checkForUpdate()` on mount unconditionally, even when the update section was hidden (as SaaS does), so the external call still ran. **What changed** - `useDesktopUpdatePopup.ts` - the startup timer now bails out immediately when `connectionModeService.getCurrentMode() === "saas"`. No mode lookup, no external fetch, no modal. - `core/GeneralSection.tsx` - the mount `checkForUpdate()` now returns early when `hideUpdateSection` is set, so hiding the section (web SaaS, managed-disabled desktop) also stops the external call. - `desktop/GeneralSection.tsx` - passes `hideUpdateSection` when `useSaaSMode()` is true, which (via the above) suppresses the settings check in desktop-SaaS too. **Why** - in SaaS the update check should never be called and no update notification should be shown; the cloud handles versioning. --- ## Checklist ### General - [x] 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/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) - [x] I have performed a self-review of my own code - [x] 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) - [x] I have run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
6c85200eb9 | Add portal access control and S3/MCP/API integration configs (#6795) | ||
|
|
467f3a86c4 | Portal policies (#6852) | ||
|
|
9d3701a585 | Fix rearrange-pages DUPLICATE producing shared page nodes (pypdf cyclic-references CI break) (#6851) | ||
|
|
c22ecc6c09 | Add counts to sources page (#6819) | ||
|
|
b38c849726 |
Portal: Procurement surface — layout rework + stateful mock backend (#6785)
Co-authored-by: aikido-pr-checks[bot] <169896070+aikido-pr-checks[bot]@users.noreply.github.com> Co-authored-by: Connor Yoh <con.yoh13@gmail.com> |
||
|
|
41f1cb2c22 |
build(deps): bump test pypdf + add translations (#6831)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com>v2.14.0 |
||
|
|
ff3e3bd0fc |
Add desktop hardware token signing and trust-aware signature validation (#6765)
# Description of Changes <img width="432" height="800" alt="image" src="https://github.com/user-attachments/assets/a01ed9ac-220c-4911-9134-b51e0f321be8" /> <img width="408" height="859" alt="image" src="https://github.com/user-attachments/assets/a9c285b6-5b75-493a-95ec-09e08d0f58f1" /> <img width="426" height="874" alt="image" src="https://github.com/user-attachments/assets/a60db96e-be93-4cc5-ba0a-63512c2857ba" /> <img width="356" height="1076" alt="image" src="https://github.com/user-attachments/assets/24d03674-94d3-40ed-99ee-73395bafae6a" /> --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
54042c8e5e | Signing UI edge-case cleanup (#6849) | ||
|
|
bb92ecc143 |
Update Backend 3rd Party Licenses + Translations and bump versio (#6794)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com> |
||
|
|
7ab30d2629 | add file share to the top workbench bar and add shared signing (#6715) | ||
|
|
276eb8f2a7 |
Add pipelines page to portal (#6818)
# Description of Changes Connect pipelines page to the backend. Note that this is really half an implementation because the portal doesn't have access to the tools list and their settings, but I can't fix that without re-architecture work, which I'll do in another PR, then come back to finish this off in a new PR. <img width="786" height="579" alt="image" src="https://github.com/user-attachments/assets/d3f06110-a35d-4d48-a2f9-1edb900c5c35" /> <img width="1232" height="519" alt="image" src="https://github.com/user-attachments/assets/9f344648-ea45-498d-9e84-9558a3999838" /> |
||
|
|
e44da5c410 |
Fix missing refresh token on desktop (#6838)
# Description of Changes Fix #6801, along with fixing policies on desktop, which would attempt to download policy outputs from the local backend instead of the server, where they actually live. I've changed the policies logic to maintain the same backend for the file retrieval as it used for the policy running, so when we support running policies locally, it should still work correctly. |
||
|
|
0beff1a92b |
feat(shared): make @shared the single home for brand logo assets (#6714)
## What
Makes `@shared` the single home for the Stirling brand logo assets.
Moves the editor's two logo sets — `classic-logo` + `modern-logo` (22
files: marks, wordmarks, favicons, login headers, PNGs) — out of
`editor/public/` into `shared/assets/brand/`, and adds a Storybook
**Brand/Logos** gallery.
## Why this shape (not a plain move)
The editor serves logos by **URL** from `public/` and switches
`classic`/`modern` by a **user preference** (`useLogoAssets`,
`manifest.json` / `manifest-classic.json`, `index.html` favicon links).
Rewiring all that to module imports would be a large, risky change to
the variant system.
Instead the editor keeps its variant system **unchanged** and just
sources the files from shared: `vite-plugin-static-copy` copies
`shared/assets/brand/{classic,modern}-logo/*` back to the served
`/{classic,modern}-logo` paths (the editor already uses this plugin for
pdfium/pdfjs assets). Single source of truth in shared, zero editor
code/manifest/markup changes.
## Verified
- **Build:** editor builds with both sets present at
`dist/{modern,classic}-logo/`; `manifest.json` + favicon refs resolve.
- **Dev:** the vite dev server serves the bridged paths —
`/modern-logo/logo512.png`,
`/modern-logo/StirlingPDFLogoNoTextDark.svg`,
`/classic-logo/favicon.ico` all return **HTTP 200** (the plugin's dev
middleware).
- Typecheck clean on core/proprietary/saas; prettier clean; `storybook
build` succeeds with the `Brand/Logos` gallery bundled.
- The portal's existing `@shared/assets` brand imports are untouched.
## Follow-ups (not in this PR)
- **Dedup:** `shared/assets/stirling-mark-*.svg` is byte-identical to
`brand/modern-logo/StirlingPDFLogoNoTextDark.svg`, and
`stirling-pdf-logo-*` is a near-twin of the modern wordmark. Reconciling
these (and re-pointing the portal) needs a designer eye on which
wordmark is canonical, so it's left out here to avoid changing the
portal's rendered logo.
- `editor/src/logo.svg` appears unused (no references) — candidate for
deletion separately.
|
||
|
|
425b76e9a7 |
fix(portal/i18n): add inline default values to account-link + billing t() calls (#6842)
## Problem The account-link / billing / Usage strings migrated to i18next in #6738 call `t("key")` with **no inline default**. When no i18next instance is initialized — which is the case in **Storybook** (the preview doesn't load the portal i18n config) — or whenever a key is missing, react-i18next renders the **raw key** (e.g. `billing.walletMeter.title`) instead of English. That's why the billing stories regressed to showing keys. ## Fix Add the English string as the `t()` default value, matching the **existing portal convention** (`AuthGate`, `Header`, `Sidebar`) and the editor: - plain → `t("key", "English")` - interpolation → `t("key", "English {{var}}", { var })` - plural → `t("key", "{{count}} …", { count })` Dynamic keys resolved via data fields carry a sibling `*Default` string passed as the default: - `LINK_INFO` badge labels → `labelDefault` (`t(info.labelKey, info.labelDefault)`) - `PdfsProcessedCard` segment legend → `labelDefault` / `descDefault` Defaults were sourced **verbatim from the merged `en-US/translation.toml`**, so the TOML stays the source of truth — the inline default only fills in when the catalogue isn't loaded or lacks the key. ## Scope All strings added in #6738: 5 account-link + 12 billing components + the Usage view (157 static call sites + the `LINK_INFO` / segment dynamic ones). No new keys; no copy changes. ## Verification - `tsc -p portal/tsconfig.json` → 0 - `eslint --max-warnings=0` (changed files) → 0 - `prettier --check` → clean - portal `vitest` → **62/62 pass** No behaviour change when i18n is initialized; Storybook and any missing-key fallback now render English. |
||
|
|
c8af6e3b7e |
feat(policies): enforce run-on-export policies on all PDF exit paths (#6788)
> **Draft / WIP** — print enforcement is still to come (see below). ## Goal A "run on export" policy must enforce on **every** path where a PDF leaves the editor, not just the main Download/Export button. This routes the remaining exits through the existing export-policy gateway (`downloadFileWithPolicy`), which runs `enforceExportPolicies` before the file leaves and is a no-op when no export policy is active. ## Audit of exit paths | Path | Status | |---|---| | Web download / export, page-editor, file-editor, thumbnails | ✅ already covered (gateway) | | **Form-fill download** (`FormSaveBar`) | ✅ fixed here — was a raw `createObjectURL` download | | **Desktop Ctrl+S save** (`useSaveShortcut`) | ✅ fixed here — was raw `downloadService` | | **Desktop save-operation-results** (`operationResultsSaveService`) | ✅ fixed here — was raw `downloadService` | | Viewer `saveAsCopy` (annotations/redactions) | n/a — in-memory version saves, not exits | | **Print** (`printActions.print`) | ⏳ pending — enforce-then-print (below) | | Web operation-results (`downloadFromUrl`) | ⏳ pending — URL-stream, needs a fetch→enforce wrapper | | Share link | excluded by design (enforce at share-creation, not recipient download) | ## In this PR All three fixes are the same pattern — route the raw download through `downloadFileWithPolicy` instead of `URL.createObjectURL` / the raw download service. ## Still to come (why it's a draft) - **Print** — enforce-then-print: on print, run the same `enforceExportPolicies`; if it changed the doc, swap the viewer to the enforced version (new version in history) and toast *"PDF updated by policy enforcement — review, then print again"* rather than silently printing a different doc; if unchanged, print. Covers Ctrl+P, the toolbar button, and embedded PDF-JS print. - **Web operation-results** (`downloadFromUrl`) — fetch the result to a blob, enforce, then download. ## Verification Typecheck (core/proprietary) + prettier clean for the changes here; desktop tsc clean for the touched files. The print UX, once added, needs a manual run with an active export policy — there's no automated path for it. |
||
|
|
82ec2acaba |
Make explicit signed and unsigned desktop CI jobs (#6840)
# Description of Changes Makes it easier to skip signing on nightlies, which we don't need to do since we're just warming the Rust cache. |
||
|
|
5e97746721 |
UX improvement for side menu bookmark, comments and attachments (#6552)
- Inline "Add bookmark" form in the bookmark sidebar (title + page, defaults to current page) - saves via /api/v1/general/edit-table-of-contents without leaving the viewer - Persistent "+ Add" rows above the list in Bookmarks, Attachments, Comments and Files sidebars (was only in empty state) - Close (X) button in every viewer sidebar header (Bookmarks, Attachments, Comments, Layers, Thumbnails) - "Add comment" button morphs into "Click a page to place… (cancel)" while textComment is armed, ESC to cancel - "Add attachment" auto-closes the attachment sidebar so you don't end up with two stacked panels - Footer link in bookmark sidebar to the full Edit Table of Contents tool for nesting/reordering - Fix: bookmark/attachment sidebars getting stuck on "Loading…" after a file swap (cache no longer caches `loading`, retry treats null bridge as not-ready) - Fix: Save silently routing to the editor tool on a fresh /read upload when `activeFileId` is still null - New Playwright tests (stubbed + live) covering Add buttons, Save flow with PDF round-trip, and close buttons <img width="720" height="1032" alt="06-thumbnails" src="https://github.com/user-attachments/assets/62298d0d-8eba-4397-9bc2-96871be29b3c" /> <img width="790" height="1062" alt="01-bookmarks" src="https://github.com/user-attachments/assets/1eb33667-c038-4b78-8711-97f354344fae" /> <img width="720" height="1032" alt="02-bookmarks-empty" src="https://github.com/user-attachments/assets/3db263ef-9550-4bac-9ffa-c729263f42c3" /> <img width="1032" height="1032" alt="03-attachments" src="https://github.com/user-attachments/assets/33580e64-020a-4e07-bf9a-595faf695fd8" /> <img width="919" height="1062" alt="04-comments" src="https://github.com/user-attachments/assets/89ef01a8-35a6-406b-825a-f04beec02f29" /> <img width="720" height="1032" alt="05-layers" src="https://github.com/user-attachments/assets/57d3cfe9-0a4c-468d-b497-ed855ddd69e5" /> --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
14245d33d1 |
feat(saas): account-link — connected self-hosted billing (Mode A) [WIP, flag-gated] (#6738)
> **Draft / WIP.** Combined-billing **Mode A** (connected self-hosted). Entirely behind `stirling.billing.account-link.enabled` (default **off** → beans absent → 404). Pairs with Stirling-PDF-SaaS PR #313 (twin migration → `v3`). ## What this does A self-hosted instance links a SaaS account in the **Portal**, gets a **device credential**, and authenticates unattended metering/entitlement with it — no long-lived user JWT on the server. The Portal then surfaces the team's **billing** (free trial → metered Processor plan) driven by the live wallet. ```mermaid sequenceDiagram participant Portal as Portal (browser) participant Supa as SaaS Supabase Auth participant Local as Self-hosted backend participant SaaS as SaaS Java (app/saas) Portal->>Supa: signIn / signUp (Supabase JS, short-lived JWT) Supa-->>Portal: JWT (SDK-refreshed, stays in browser) Portal->>Local: hand JWT (same-origin) Local->>SaaS: POST /account-link/register (Bearer JWT, leader) SaaS-->>Local: { device_id, device_secret } (secret once) Note over Local: store device_secret server-side loop unattended Local->>SaaS: /api/v1/instance/** (X-Device-Id + X-Device-Secret) SaaS-->>Local: entitlement / gate decision end ``` **Auth model:** human auth = Supabase JS (ephemeral JWT, kept for attended portal features). Durable instance auth = a team-bound **device_id + secret** (SHA-256 stored, shown once), non-user `ROLE_LINKED_INSTANCE`, path-scoped to `/api/v1/instance/**`. Instance binds to a **team**, never a user. ## Billing surface (Portal · Mode A states) `Usage & billing` is state-driven by the link/subscription dimension and built to the marketing designs, sharing one component layer across states: - **Unlinked** → link-account prompt. - **Linked · Free** — the *Processor trial*: a one-time 500-PDF free grant ("Process 500 PDFs free, then $X/PDF"), the team's free-editor fleet, and a leader-only **Switch on the Processor →** (embedded Stripe Checkout). - **Linked · Subscribed** — the *Processor plan* dashboard: PDFs-processed split (API / Agents / Automation), **spend this month** vs. a **spend limit** meter with a run-rate projection and an **in-place cap editor** (preset buckets + suggested value + guardrail), Stripe **invoices** (with billed PDFs per invoice), and the default **payment method**. Card / subscription changes deep-link to Stripe's hosted portal. Manual PDF editing is always free — only Automation / AI / API is metered; a `$0` cap blocks all metered work (≠ "no cap"). **Shared, not duplicated:** the editor-fleet card, the Enterprise upsell, and the meter (`@shared/billing` `MeterBar`) render in both the free and subscribed views; money/cap math lives once in `@shared/billing`. The page header is a sticky, full-bleed bar. **New SaaS reads** (defensive — degrade to empty/"—" when the Stripe mirror lacks a table, never 500): - `GET /api/v1/payg/payment-method` — default card (brand / last4 / expiry) from `stripe.payment_methods`. - Invoice **PDFs processed** — billed line-item quantity from `stripe.invoice_line_items`. ## Progress - [x] Schema: `V22 linked_instance` (+ Supabase twin in #313) - [x] `AccountLinkController` register / list / revoke (leader-only, team from caller) - [x] Device-credential filter (path-scoped, constant-time, revocation-aware) + `SupabaseSecurityConfig` wiring (conditional) - [x] `GET /api/v1/instance/whoami` + **`/entitlement`** (reuses `EntitlementService`/`TeamBillingService`) + tests - [x] Self-hosted backend (`app/proprietary`): orchestrator + instance gate (dark + **fail-open**) + tests - [x] Portal: in-app Supabase login modal + register hand-off + `LinkContext` (unlinked default) + "Linked instances" view — all `@shared` Storybook components - [x] **Portal billing surface** — free (Processor trial) + subscribed (Processor plan) Usage views to marketing spec; link-state derived from the **live wallet**; in-place cap editor; over-cap banner - [x] **SaaS reads** — payment-method endpoint + invoice billed-units (defensive `stripe.*` mirror DAOs) + tests - [x] Orphan guard: block leaving/accepting away from a team whose departure orphans its linked instances - [ ] Metering Step 2 (lease + reconcile loop) + bounded fail-open cutoff - [ ] Proprietary hardening (SaaS base-url config, secret-at-rest, finer billable classification) + HTTP integration test - [ ] Cross-repo Stripe lifecycle certified end-to-end (subscribe → meter → cancel → 402) - [ ] Admin ⟺ SaaS-leader enforcement (separate portal-team-mgmt workstream) ## Verification — all green | Gate | Result | |---|---| | `STIRLING_FLAVOR=saas :saas:test` | BUILD SUCCESSFUL (account-link + payg, incl. `PaygPaymentMethodControllerTest`, `PaygInvoicesControllerTest`) | | `:proprietary:test` | BUILD SUCCESSFUL (account-link + entitlement cache/interceptor) | | portal | tsc 0 · eslint 0 · **vitest 55** · storybook build (all billing stories) | | frontend post-sync | typecheck shared + portal + editor (saas + desktop): 0 | ## Screenshots — billing UI _Latest Storybook renders (Portal/Billing). Drag each capture below its caption — kept out of the repo._ **Linked · Free — Processor trial** <img width="1648" height="503" alt="01-free-processor-trial" src="https://github.com/user-attachments/assets/afe6238a-d3b4-47fd-8ea2-cbaed8b0a653" /> **Linked · Subscribed — Processor plan dashboard** <img width="1648" height="930" alt="02-subscribed-processor-plan" src="https://github.com/user-attachments/assets/329e6808-a9a9-4e65-99af-5a8a5e6bf4ab" /> **Spend limit — in-place cap editor** <img width="1648" height="411" alt="03-spend-limit-editor" src="https://github.com/user-attachments/assets/acc95096-bf8e-4ab0-a32c-3c20dc94f816" /> ## Review feedback applied Reworked the portal after first-pass feedback: linking signs in via the **shared Supabase login** (SSO + email/password) — no bespoke form; the **device secret is never shown in or sent to the FE** (the local backend registers + stores it server-side); billing copy reads **PDFs**, not "units"; the wallet surface uses **`@shared` components** matching the SaaS Plan page. Re-verified including an assertion the link response carries no `deviceSecret`/`deviceId`. **Synced onto unified auth + in-app login (2026-06-23).** Merged `main` incl. **#6725 unified auth** (`frontend/shared/auth`); the link flow uses a shared `useSupabaseLogin` hook + `SupabaseLoginForm`, a portal `LinkAccountModal`, and `useAccountLink.completeLink(session)` (+ on-mount SSO redirect-return). Config: `VITE_SAAS_SUPABASE_URL` + `VITE_SAAS_SUPABASE_ANON_KEY`. The local `/account-link/link` call carries the Spring admin bearer with the SaaS JWT in the body. **SSO** needs the SaaS Supabase project to allow-list the portal redirect URL (email/password works without it). ## Assumptions / open - **Proprietary remains a scaffold** (placeholder SaaS base-url, plaintext device secret at rest, coarse billable classification). - Payment-method + invoice-quantity render only when `stripe.payment_methods` / `stripe.invoice_line_items` are in the Sync-Engine target (confirm in the Supabase/Sync-Engine config); otherwise they degrade gracefully. - A self-contained local HTML report + manual E2E runbook live in `notes/account-link-report/` (dev artifacts, outside the repo). --------- Co-authored-by: James Brunton <jbrunton96@gmail.com> |
||
|
|
84739e8b0e |
Align settings.yml defaults and fix dead/mismapped settings (#6816)
# Description of Changes Align settings.yml defaults and fix dead/mismapped settings --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
0996277c41 |
Brand MSI installer and rename display name to Stirling PDF (#6764)
# Description of Changes Add icons to stirling PDF installer and changed app name from Stirling-PDF to Stirling PDF <img width="495" height="387" alt="image" src="https://github.com/user-attachments/assets/6f23b501-d765-43a6-a713-b330ea199a04" /> <img width="495" height="387" alt="image" src="https://github.com/user-attachments/assets/83d50ac9-2220-474b-8269-bfcfad01166c" /> <img width="495" height="387" alt="image" src="https://github.com/user-attachments/assets/f0113ef5-9567-46d0-820c-0891d33b2355" /> vs old <img width="495" height="387" alt="image" src="https://github.com/user-attachments/assets/d50fa652-cb42-4668-b951-4f2ce52eba14" /> <img width="495" height="387" alt="image" src="https://github.com/user-attachments/assets/b113890b-f06d-4dea-9738-1b885a9ba125" /> <img width="495" height="387" alt="image" src="https://github.com/user-attachments/assets/3b6792aa-48a5-425f-9ae2-13938fd297a5" /> --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
d508bc41bf |
Fix PR docker CI when the base image changes (#6809)
# Description of Changes - Fix PR CI for base-image changes: the embedded build's buildx container builder could not resolve the locally-built `stirling-pdf-base:pr-test` and tried to pull it from a registry, failing the build - `test-build-docker.yml`: when the base changed, build the embedded image with the docker driver (`docker build`) so the locally-built base resolves from the daemon image store - `docker-compose-tests.yml`: when the base changed, skip the buildx container builder + gha cache so `test.sh`'s local base build resolves via the default docker driver --- ## Checklist ### General - [x] 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/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) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs (if functionality has heavily changed) - [ ] I have read the section Add New Translation Tags (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached ### Testing (if applicable) - [ ] I have run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally --------- Co-authored-by: James Brunton <jbrunton96@gmail.com> |
||
|
|
6ff910f26c |
Expand any type linting in frontend (#6808)
# Description of Changes Continued effort to expand linting scope to ban the `any` type in our codebase. This PR pulls in a lot of subfolders into the linting scope, because the excluded list was getting short enough that it was feasible to move a layer down. I then fixed all the trivially fixable `any` type violations in the subfolders, which just required local changes to the one file. The aim of this PR is more to expand the scope to all the folders we can that already avoid `any` types, rather than actually fix violations. |
||
|
|
013f145462 |
Upgrade to TS7 for local type-checking (#6815)
# Description of Changes We can't convert to TS7 completely yet because it lacks the TS API, so ESLint and some of our scripts don't work, but we can do [what the TS team suggest and run TS6 and TS7 side-by-side](https://devblogs.microsoft.com/typescript/progress-on-typescript-7-december-2025/#compiler). When we do that, we take the `task frontend:typecheck:all` job from ~76s to ~13s, and everything else continues to work as it did before. I've set it so that CI will still use TS6 for the time being and locally we use TS7 out of an abundance of caution because CI time doesn't really matter but local time does. I do think it was a bit pointless doing that since the TS team claim the type checking performs identically, but we might as well have it like that for now. If it happens to go badly locally for any devs, they can use `CI=true task frontend:typecheck` to revert to use TS6 trivially. |
||
|
|
eea9696bd4 |
Actually build the frontend for Playwright nightlies (#6817)
# Description of Changes [Our nightlies have literally never passed before](https://github.com/Stirling-Tools/Stirling-PDF/actions/workflows/nightly.yml). As far as I can tell, that's because the frontend was never being built, so the Playwright tests would just never start up. I've forced a nightly run from this branch, and the Playwright tests still fail, but for legitimate failures now. It's a separate job to track down why they're actually failing, so I'm leaving that for followup work. |
||
|
|
3f7e898c69 |
Add sources service and frontend (#6774)
# Description of Changes Redesign policies backend to treat sources a lot closer to how the frontend imagined them working (they're persistent now and have an API). Then connect the portal to the sources when mocks are off to allow for source creation in the UI. It's not particularly useful to do that right now because there's no policies UI, but I've tested manually that sources set up in the UI are usable by policies created via the API. I had to change the portal so that when mocks are off, it doesn't just hard crash when attempting to connect to all the backend APIs that don't exist yet. It'll still log the errors, but just continues on rendering the UI now. I also changed all the policies backend APIs to be gated behind a flag instead of behind the SaaS profile. This is because we haven't yet got the payment model sorted, but we're going to need this stuff running self-hosted to be able to test it locally. |
||
|
|
def3cf79f6 |
More desktop CI optimisations (#6786)
# Description of Changes - Change the nightly build to not sign any of the desktop builds, since we just care about the compiled code. The restored code will still be signed dependent on the OS in the PR builds. - Change RPM Linux to use zstd for compression because the one it was using runs really slowly, and the Jar is already compressed so it makes basically no difference (arguably we shouldn't compress at all) - ~Switch to consistently use Depot for Docker caching to stop filling up the GHA cache and evicting the Rust cache~ Decided against switching to Depot because we're probably doing another PR to remove Depot altogether in the near future |
||
|
|
501a7199e0 |
Add bulk comment and annotation clearing to editor (#6792)
# Description of Changes Closes #6695 This PR adds bulk cleanup actions for comments and annotations in the PDF editor, while tightening the save and navigation behavior around annotation edits. ### Comments sidebar Adds a “Clear all comments” action to the comments sidebar overflow menu. The action opens a confirmation modal before clearing sidebar comments and replies. The implementation distinguishes between standalone comment annotations and comments attached to existing visual annotations. Standalone comments and replies are removed from the document, while comments attached to markup, shapes, ink, or other visual annotations are cleared from the sidebar without deleting the underlying annotation itself. This preserves the visible document markup while removing the comment metadata and persisted comment contents. The comments sidebar state is also reset after clearing, including draft comments, reply drafts, edit state, and open confirmation/delete modal state. ### Annotate tool Adds a document-level “Clear all annotations” action to the Annotate tool. The action is exposed through the annotation panel’s overflow menu and uses a confirmation modal before removing annotations. The clear operation is routed through the existing annotation API bridge and delegates to EmbedPDF’s document-level annotation clearing API. The UI handles unavailable annotation state, successful clears, and failures. After annotations are cleared, the editor resets annotation interaction state, exits placement/selection-specific state, returns to select mode, and marks the document as having unsaved changes only when annotations were actually removed. The user can then persist the removal through the normal Save Changes flow. ### Save and navigation hardening Improves the viewer save/apply flow used by annotations and manual redactions. Save operations are now deduplicated while an apply operation is already in flight, preventing duplicate exports or duplicate file consumption when users trigger save/navigation repeatedly. The global unsaved-changes navigation modal now waits for “Apply & Leave” to complete successfully before navigating. If saving fails, the modal keeps the user in place instead of leaving with unsaved edits still present. The Annotate panel also prevents “Save Changes” and “Clear all annotations” from running concurrently. <!-- Please provide a summary of the changes, including: - What was changed: - Why the change was made - Any challenges encountered --> --- ## Checklist ### General - [X] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [X] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/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) - [X] I have performed a self-review of my own code - [X] 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) - [X] 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) - [X] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) Clear all comments : <img width="310" height="397" alt="image" src="https://github.com/user-attachments/assets/d1682611-13f8-4f40-aa77-44b37450e56e" /> Clear all annotations: <img width="284" height="549" alt="image" src="https://github.com/user-attachments/assets/e4049bc1-f07b-4b36-b08e-ad6d6b86fe62" /> ### Testing (if applicable) - [X] I have run `task check` to verify linters, typechecks, and tests pass - [X] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
bc6f1a1ff5 | Add login agreement disclaimer feature (#6766) | ||
|
|
d06d3cabaf | chore: update svg conversion and database import handling (#6796) v2.13.2 | ||
|
|
b040277220 | fast-path local PDF transport and reduce chat re-renders (#6798) | ||
|
|
f715a73f1b |
build(deps): bump astral-sh/setup-uv from 8.1.0 to 8.2.0 + translation files (#6748)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
5be9a0e1df |
fix desktop bundles (#6773)
# Description of Changes Changes - Use 127.0.0.1 instead of localhost for the local backend. The bundled backend starts on a random port and binds the IPv4 wildcard, but the frontend health-checked http://localhost:{port}. On macOS (and some Linux) localhost resolves to IPv6 ::1 first, so the connection is refused and every backend-dependent tool shows "backend offline" even though the backend started fine. Switched getBackendUrl() and the health-check URL to the 127.0.0.1 loopback literal (already in the Tauri HTTP capability allowlist, and what the OAuth loopback server already uses). Client-side tools were unaffected, which matches the reports. - Fail the desktop build when the bundled JRE is older than the app JAR. The app JAR is compiled for Java 25, but the bundle could ship an older runtime/jre (jlink:runtime short-circuits on an existing runtime, and nothing checked its version), producing UnsupportedClassVersionError at launch so the backend never starts. Added a jlink:verify task that reads the jlink release file and fails the build if the bundled JRE major is below REQUIRED_JAVA (25, kept in sync with build.gradle modernJavaVersion). It runs after the runtime is staged - including the short-circuit reuse path that lets a stale JRE slip through. Cross-platform Node script, no new dependencies. --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
f7f7b8790e |
fix update notification visibility and install flicker (#6776)
# Description of Changes - Closes #6754 - Update popup now hidden on mobile, for non-admins, and never on SaaS - Respects admin "Show Update Notifications" setting (`showUpdate` / `showUpdateOnlyAdmin`, now default on) - Fixes update modal flickering during desktop install --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
26021425e3 |
chore(ci): upgrade Gradle to 9.6.0 across workflows, Docker builds, and wrapper (#6790)
# Description of Changes ## What was changed - Updated all GitHub Actions workflows using Gradle from older versions (9.3.1 and 9.5.1) to Gradle 9.6.0. - Updated the Gradle Wrapper distribution URL to use Gradle 9.6.0. - Updated all Gradle-based Docker build stages to use the `gradle:9.6.0-jdk25` image and corresponding image digest. - Aligned CI, Docker, and local development environments on the same Gradle version. - Included the regenerated `gradlew` script changes produced by the Gradle wrapper update process. ## Why the change was made - Ensures consistent Gradle versions across local development, CI workflows, and Docker builds. - Takes advantage of the latest Gradle 9.6.0 improvements, fixes, and compatibility updates. - Reduces the risk of version mismatches causing build or deployment inconsistencies. - Simplifies maintenance by standardizing the build toolchain throughout the repository. --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
e35594f946 |
chore(build): centralize Gradle dependency version management (#6499)
# Description of Changes This change centralizes several dependency version declarations into shared Gradle version properties and updates module build files to reference those properties instead of hardcoded version strings. ### What was changed - Added centralized version properties in the root `build.gradle` for: - commons-io - commons-lang3 - rhino - okhttp BOM - gson - guava - bucket4j - archunit - batik - jpdfium - JWT - AWS SDK - Testcontainers - Replaced hardcoded dependency versions across multiple modules with shared version variables. - Updated `resolutionStrategy.force` declarations to use centralized version properties. - Updated dependency constraints and BOM references to use shared version variables. - Removed module-specific duplicate version declarations from `app/proprietary/build.gradle`. - Standardized dependency declarations across `common`, `core`, `proprietary`, and `saas` modules. ## Why the change was made - Reduce duplication of dependency version definitions. - Simplify future dependency upgrades and maintenance. - Ensure consistent dependency versions across all modules. - Improve readability and reduce the risk of version drift between subprojects. - Make security-related dependency overrides easier to maintain from a single location. --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
8a0b12b5ab |
Remove ffmpeg from published Docker images (#6791)
## Summary Published Docker images (`stirling-pdf:latest`, `:2.13.1`) still shipped the full `ffmpeg` package even though it was disabled in source back in #6053. **Root cause:** `push-docker.yml` passed a hardcoded `BASE_VERSION=1.0.0` build-arg for the regular image, overriding the Dockerfile's `ARG BASE_VERSION=1.0.2` default. Base `1.0.0` is the original base that still does the explicit `ffmpeg` apt install, so the published image never picked up the removal. |
||
|
|
60fff188a6 |
fix(team): hide users already assigned to the selected team (#6760)
# Description of Changes
# Description of Changes
- What was changed
- Filtered the "Add Member to Team" user picker so users who are already
members of the selected target team are no longer shown.
- Applied the same filtering in both team management entry points:
- `TeamsSection`
- `TeamDetailsSection`
- Kept users in other teams visible, so they can still be moved into the
selected team.
- Why the change was made
- The modal was showing users who were already part of the target team,
which made the action misleading and allowed redundant selection.
- Hiding already-assigned users keeps the UI aligned with the actual
action: adding new members to the team
before:
<img width="442" height="425" alt="image"
src="https://github.com/user-attachments/assets/9faf991f-a7d3-4a48-91cd-f47730decde8"
/>
after:
<img width="430" height="382" alt="image"
src="https://github.com/user-attachments/assets/f8291172-feb6-4d8d-b536-eebf752b764b"
/>
---
## 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/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 run `task check` to verify linters, typechecks, and tests
pass
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing)
for more details.
|
||
|
|
41181c9da1 |
Redesign tool config types to avoid any typing (#6582)
# Description of Changes Fixes one of the main causes of `any` typing left in tools, the way that we register tool parameters in the registry. Currently, it just accepts tool params via `any`, but instead we can explicitly change them to `Record<string, unknown)`, so on the way back out they can more safely be cast back to their correct type when known. One consequence of this is that I had to redesign the way we special-case the Convert tool, which previously was a different shape than all the other param types. Now it's just got optional parameters on it, which isn't quite as type-safe as before, but it does mean all tools are a consistent shape now, which I think is worth the tradeoff. |
||
|
|
8e485801c9 |
change policies ui (#6683)
• Removed colors from policies to make them look more professional. • upgraded to enterprise link to contact us. • Hid inactive policies from users (Kept for admin and team lead). • Closing policies had wrong arrow, made a standard component for chat, tools and policies header. |
||
|
|
436afa51d7 |
Always use the modern logo in the SaaS build (#6775)
## What Make the **SaaS** build always use the modern logo, so the classic logo can no longer appear anywhere in the SaaS app. This is a minimal, SaaS-only alternative to the full classic-logo removal PR (~80 files). **OSS (`core`) and proprietary builds are untouched** — they keep the full modern/classic variant system, including the admin _Logo Style_ picker. ## How A single SaaS-layer override shadows the core hook: - `frontend/editor/src/saas/hooks/useLogoVariant.ts` → returns `"modern"` unconditionally. In the SaaS build the `@app/*` alias cascade resolves `@app/hooks/useLogoVariant` to `src/saas/*` before `src/core/*`, so this shadows the core implementation (which otherwise resolves the variant from the stored user preference or the server `logoStyle`). ## Why one file is enough All logo rendering funnels through `useLogoVariant()`: - `useLogoAssets()` → favicon, web manifest, apple-touch icon, wordmark, `logo512`, tooltip logo — consumed by `BrandingAssetManager` (which sets `<link rel="icon|manifest|apple-touch-icon">`), `Wordmark`, `LogoIcon`, `Tooltip`. - `useLogoPath()` → the no-text logo SVGs. - The login-carousel slides (`buildLoginSlides`) receive the variant from `AuthLayout`, which calls the hook. Everything else that references a logo in SaaS already hardcodes `modern-logo` (`index.html`, the SaaS `Login`/`Signup`/`AuthCallback`/`OAuthConsent` routes, cloud onboarding, account/MFA QR logos). The only hardcoded `classic-logo` reference — the admin _Logo Style_ picker in `AdminGeneralSection` — is **not shipped in SaaS**: `createSaasConfigNavSections` builds from the core nav sections and never includes the proprietary admin sections. `manifest-classic.json` and the classic assets remain in the shared `public/` folder (served by all builds) but are never referenced in the SaaS bundle. ## Test plan - [x] `task frontend:typecheck:saas` — clean - [x] `eslint` on the new file — clean |
||
|
|
0a29186ed6 |
Add JUnit tests to raise coverage across all modules (#6782)
# Description of Changes AI generated junit tests --- ## 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/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 run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details. |
||
|
|
101502cf4f |
Upgrade to TypeScript 6 (#6772)
# Description of Changes TS6 introduced backwards-incompatible changes which affected us a little bit. Other than that, I don't think it significantly changes things for us, but we will need to deal with these breaking changes to be able to upgrade to TS7 (the version written in Go, so dramatically faster), so I'd rather do the work now before TS7 actually releases. Main things I've done: - Removed the use of `baseUrl` in the `tsconfig.json` files - Explicitly provide the `node` types where needed - Explicitly reference the un-referenced but required Google API types - Dropped the installation of `madge` which we weren't using and wasn't directly compatible with TS6 - Updated the `i18next` packages for explicit TS6 compatibility - Explicitly override `tsconfck` to force TS6 compatibility since we can't upgrade it. We're only using that for `vite-tsconfig-paths` and it all still seems to work fine, so I don't think this is an issue. I think we can theoretically drop `vite-tsconfig-paths` when we upgrade to Vite 8 ([because it supports `paths`](https://v8.vite.dev/guide/features#paths)), but that's a bigger job than I want to do in this PR |