* [web] add endpoint for resolving a project for writes from tpds
* [web] return historyId from new endpoint for resolving projects
* [web] add zod validation to new endpoint for resolving projects
GitOrigin-RevId: 0e607e56442117a4150a08373169c44b53dd4fdf
* Remove `plans-2026-phase-1` from subscription module
* Remove code related to `plans-2026-phase-1`
* Remove `SplitTestUserGetter.getProjection`
* Update tests
* Remove last mentions of `plans-2026-phase-1`
* In test, wait for `_updateCustomerIoSubscriptionProperties` to be done
* Remove `purchaseAddon` test
* Remove AI-addon tests
* Fix `_quotaTierToAllowance` throwing on zero-grant tiers
`!quota` treated `0` as invalid, so `basic` (grant 0) threw. Check `typeof quota !== 'number'` alone. Unmasked once branch removed the split-test branch that skipped this path.
* Extract `waitForCustomerIoSync` helper in FeaturesUpdater tests
* https://github.com/overleaf/internal/pull/34771#discussion_r3552882875
GitOrigin-RevId: 0fe0e41b7a4105a3c4739214e2fffb77e91dbc42
* github-sync: only swallow permanent revocation failures during unlink
404 (token gone) and 422 (token issued under a mismatched client_id,
the confirmed cause of #35108) are treated as safe to proceed past;
any other revocation error now aborts the unlink instead of silently
deleting the local credential row, so a token that might still be
live isn't orphaned by a transient GitHub failure.
* web: surface genuine github-sync unlink failures instead of a 500
When GithubSyncApiHandler.unlink rejects for a reason other than the
permanent 404/422 cases now handled by github-sync, show an error
notification on the settings page instead of crashing the request,
mirroring the existing projectSyncSuccessMessage session-flash pattern.
* github-sync: detect expired credentials in user status check
getStatus now validates a stored token against GitHub (GET /user)
before reporting it as linked. A GithubInvalidCredentialsError (401)
now surfaces as expired: true alongside enabled: true, distinguishing
a dead token from a genuinely working link. Any other validation
failure fails open and reports enabled: true as before.
* web: propagate github-sync expired status through to the client
Thread the new expired field from github-sync's status endpoint
through GithubSyncController.getUserStatus and the settings-page
injectUserSettings middleware, and extend the corresponding
TypeScript types on both the app and frontend side.
* web: show a re-link path on the settings widget when github credentials expire
The widget now checks expired status: it shows an error indicator
with a "connection expired" message and renders the Link action
instead of a dead-end Unlink button, since relinking upserts a fresh
token regardless of the stale row.
* web: keep unlink available for expired github credentials
Some users just want to remove an expired connection rather than
relink it. Keep Unlink as the primary action regardless of expired
status, and surface the relink path as an inline link next to the
expired message instead of replacing the primary action.
* web: correct the github unlink confirmation warning
Unlinking never touches a project's githubSyncProjectStates row,
regardless of whether the credential was healthy or expired -
verified by tracing unlinkAccount/deleteUser and confirming no other
code path deletes project sync state on account unlink. Sync pauses
until relink, but no project loses its GitHub connection, so the
warning text was simply wrong; corrected rather than adding a
separate expired-specific message.
* web: add Storybook story for expired github-sync credentials
Covers the new expired state alongside the existing NoFeature,
Unlinked, Linked and Error stories for the settings widget.
* simplify: collapse duplicated branches and extract session-flash helper
- Merge the near-identical 404/422 checks in _revokeToken into one
status-set check.
- Use optional chaining instead of null-guard ternaries in
GithubSyncMiddleware.
- Extract popSessionValue() in UserPagesController to de-duplicate the
read-then-delete session flash-message pattern, now used 3 times.
* review-self: close test coverage gaps found in self-review
- AuthenticationController: cover 401/403 revocation responses and a
plain network error with no .response, alongside existing 404/422/500.
- GithubSyncController: assert projectSyncErrorMessage stays unset on
the unlink success path.
- UserPagesController: cover projectSyncErrorMessage set-then-cleared
and absent-stays-undefined cases.
- Add GithubSyncMiddleware.test.mjs (previously untested): not-logged-in,
successful status fetch, and callback-error branches.
- Cypress: cover cancelling the unlink confirmation modal while expired.
- Storybook: add ErrorWhileUnlinked story for the disabled-Link +
error-indicator combination.
* review-self: fix audit-log ordering, cache getStatus validation safely
- GithubSyncApiHandler: write the link-github/unlink-github audit log
entry only after the corresponding github-sync API call succeeds,
instead of before (resolves the discrepancy tracked in issue 3354).
- UserController/UserManager: cache getStatus's live token-validation
result for 5 minutes to cut down on redundant GitHub API calls,
with an optimistic-lock write (matched against the encrypted token
that was actually validated) so a relink can never be overwritten by
a stale in-flight validation of the old token.
- github-integration-linking-widget: dedupe the relink href against
the linkPath already passed to IntegrationLinkingWidget.
* web: surface expired github credentials proactively in the sync modal
The modal previously only showed the reauthorize prompt after a real
GitHub API call failed with 401 mid-action. It now also checks the
expired field already returned by the status endpoint and shows the
same prompt immediately on open, before ever rendering the export
form against a token known to be dead. Extracted the existing
reauthorize markup into GithubCredentialsExpired so both call sites
share it.
* github-sync: avoid double-fetching the credential doc in getStatus
getStatus called UserManager.getUser, then getAuthToken which
internally fetched the same document again. Add getAuthTokenFromUser
to decrypt from an already-fetched doc and use it in getStatus,
removing the redundant Mongo query and the now-unreachable
GithubUserNotLinkedError handling (the user doc's existence was
already confirmed by the first fetch).
* github-sync: make expired-token handling reactive, drop proactive getStatus validation
Reverts getStatus in the github-sync service to a pure DB check — no live
GitHub API call, no 5-minute cache, no token_expired/token_validated_at
fields. The expired state is already surfaced reactively: the unmerged-commits
fetch on modal open returns 401 when the token is dead (handled by the existing
case 401 branch), and ExportToGithub handles 401 from the orgs call. The
proactive check added complexity (caching, optimistic-lock writes) without a
meaningful UX gain over the reactive paths.
Removes the expired indicator from the settings widget and the proactive
GithubCredentialsExpired screen from the modal's pre-flight check. The
github_sync_expired locale key is removed as it is no longer referenced.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* github-sync: show reauthorize prompt when push/pull fails with expired credentials
When a merge (push or pull) returns 401, GithubSyncMergeAction now renders
GithubCredentialsExpired with the Reauthorize button instead of the raw
"GithubInvalidCredentialsError" string that was previously falling through
to the default error branch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* github-sync: wrap all async controller handlers with expressify
Without expressify, an unhandled throw from an async route handler
(e.g. a token decryption failure in the github-sync service producing a
non-4xx error that _reportError re-throws) becomes an unhandled rejection.
Express never sends a response and the modal is left stuck on loading.
expressify catches the error and passes it to next(), so Express's error
handler sends a 500 and the frontend can surface it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* removing redundant tests
* removing getAuthTokenFromUser function
* removing redundant key
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
GitOrigin-RevId: 0d9a314bf70bea9e6037593f2a6f8b8d1f2c6e71
* filtering out venv directories
* also exclude .venv directories and sync all pattern copies
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
GitOrigin-RevId: 6634d9780da44f90c6777347d52def9a854bd29f
* [web] AI Feature controls for managed groups
Adds a Feature Controls section to the group settings with a switch to control whether AI features are enabled or disabled
GitOrigin-RevId: c5d5ed80c0cc3435075bb2c58b43fc08192dd46b
* Merge intermediate component wrappers into OL-prefixed components
* Replace all intermediate wrapper consumers with OL-prefixed components directly
* Fix jsx/js files still importing deleted shim components
* Remove duplicate OLNotification imports left by first pass
* Rename OLTagIcon to TagIcon, remove OL prefix
* Rename OLDropdownMenuItem to DropdownMenuItem, remove OL prefix
* Remove OLNotification, use Notification directly
* Move Notification to the main shared component folder
* Update tag-icon import path out of ol/
* Move TagIcon to the main shared component folder
* Update dropdown-menu-item import path out of ol/
* Move DropdownMenuItem to the main shared component folder
* Fix dropdown-menu-item import path to dropdown/ subfolder
* Remove BS5 alias prefixes from shared components
* Restore notification-list wrapper in Notification component
* Add translation for loading button
* Remove redundant import aliasing
* Resolve conflicts
* Restore notification container `notification-list`
GitOrigin-RevId: 24a5af18599a3e02ac6fd61c09cf5a49ef6e0020
* update doc links to point to docs.overleaf.com instead of the old learn wiki
* fix broken link to LaTeX positioning wiki article in figure modal help
* point figure positioning help link to the docs.overleaf.com page
* point figure/table label help links to specific anchors on the captioning-and-referencing-figures doc page
* point figure modal error-help link to the graphicx-loading doc page
* normalize target/rel on docs.overleaf.com links opened in a new tab
* open figure modal and SSO help links in a new tab now that they point off-site
* add eslint rule enforcing rel=noopener noreferrer on docs.overleaf.com links
* extend require-rel-for-docs-links to also check OLButton
* add lint script catching missing rel on docs.overleaf.com links in pug templates
* fix require-rel-for-docs-links autofix crash on valueless rel attribute
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* add regression test for require-rel-for-docs-links valueless-rel autofix
* revert `target=_blank` on figure modal and SSO help links
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
GitOrigin-RevId: b6111341e1080fd7e4b42f6a1a18c27ea0fd7d8c
* [web] Minor fixes for AI Disabled state
- Applies opacity to disabled spark icons
- Forces AI controls to be hidden on View state
* Removed redundant check
GitOrigin-RevId: a1389bec3e80a396c77a22294b1d921b4116a75c
* Add png to pdf converter for optimising image loading in pdftex
* refactor
* move fixtures
* refactor and add unit tests
* Remove gamma correction from PNG processing and update related tests
* Add crc32fast dependency and enhance PNG processing tests
* Add fixture test cases for PNG processing
* fix alpha channel to match pdftex
pdftex always uses an 8 bit alpha channel in the output even for 16 bit images
* Refactor PNG processing to use Option for alpha stream and update related logic
* Enhance PDF writing by adding DecodeParms for alpha stream and optimize PNG encoding process
* Add pixel dimensions support in PNG processing and PDF writing
* [copybara] move clsi excludes
* [clsi] move gitignore rules
* [png2pdf] move into dockerfiles folder
* [png2pdf] use atomic writes
* [clsi] integrate png2pdf
* [saas-e2e] add coverage for png2pdf
* [png2pdf] make compatible with seccomp profile in clsi
* [copybara] remove exclude following move of png2pdf
* [copybara] remove spurious excludes
* fix broken detection of malformed chunk headers
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* [project-history] add build script flag for depending on doc-updater types
* [png2pdf] run tests as part of clsi pipeline
* [png2pdf] fix calculation of PDF page size
* [web] put png2pdf behind feature flag and make it opt-in
* [web] fix ClsiManager.promises.sendRequest invocation after merge
* extend is_copy_safe function to follow pdftex
see the conditions in pdftex's writepng.c
https://svn.tug.org:8369/texlive/trunk/Build/source/texk/web2c/pdftexdir/writepng.c?revision=78081&view=markup#l575
the criteria are not an exact match because the png crate does not support all the
png chunk types
https://github.com/image-rs/image-png/issues/116
if the criteria result in a png being converted or skipped the final result should be the same.
in one case the conversion will be done by pdftex (at runtime)
in the other case the conversion will be done by png2pdf -
both conversions should give the same result.
* include tests in png2pdf Dockerfile
* [clsi] explicitly disable png2pdf conversion for project conversion
* [clsi] png2pdf: count converted files
* [png2pdf] bump date in docker image tag
* [web] make draft-setting option wider when png2pdf is available
---------
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: d0d952ee009bf93c72bba2ffe763ae0160d396e4
* [web] add frontend tests for sharejs transform
* [web] extend tests for sharejs transform to flush eventually
* [web] full coverage for sharejs transform
* [web] add tests for sharejs events
* [web] add tests for sharejs callbacks
* [web] avoid sending empty sharejs op
* [web] add tests for resending after reconnecting
* [web] avoid resending of empty sharejs op after reconnecting
GitOrigin-RevId: 226fe47a7069cb877fd5a60454f86cc5855d9a0e
\tag*{...} (amsmath's unnumbered tag) incorrectly triggered an "open
inline math \( used inside existing math mode" warning when its
argument contained inline math, e.g. \tag*{\(\dagger\)} or
\tag*{$abc$}. \tag{...} without the star already worked.
The linter marks \tag's argument group as text-mode so nested math
delimiters are allowed, but the literal * between \tag and { was
tokenized separately and reset that flag before the argument group
was reached. \tag now consumes an immediately following * so the
text-mode flag survives to the argument group.
* [migrations] only apply non-blocking migrations in CI
* [migrations] use "yarn run migrations" instead of "npm run migrations"
GitOrigin-RevId: d9f96db398adf2febcd82333295fb8d5eab741bb
* [web] _getUserCompileLimits: use owner.analyticsId directly
* [web] deduplicate project lookups for compile requests
* [web] add test case for prefetched project
GitOrigin-RevId: 0e140619c874accf8673153ed90af2ce70cf9234
* [web] split-tests: add helpers to using an already fetched mongo user
* [web] split-tests: add ignoreOverrides option to getAssignment
* [web] split-tests: reuse already fetched mongo users where possible
* [web] notifications: fetch users in bulk for split-test assignment
* [web] split-tests: use session for assignment where possible
* [web] split-tests: pass req/res down into domain-capture hook
* [web] split-tests: explicitly throw early
* [web] split-tests: refine jsdoc types
* [web] mark analyticsId and labsProgram as required in user model
* [web] split-tests: refine jsdoc types
* Revert "[web] split-tests: pass req/res down into domain-capture hook"
This reverts commit 897a158384cd2b3e416fc34495b20d1e2a0e68f0.
GitOrigin-RevId: ea4afd15c2506f369827b5193fd16d220d3c7d0e
* [web] adopt free/premium compile backend class
* [rails] adopt free compile backend class for pdf conversion
GitOrigin-RevId: e12c99a27363f5654132c2fcdc6c5d8ccc591868