Document content stopped going through Django when the collaboration
server took it over, and these two are what the move left behind. Both
are unreachable rather than merely unused, so they are removed instead
of being carried forward.
useUpdateDoc sent websocket: true whenever the provider was synced, to
unlock a cache lock the backend used to hold while another user was
connected. That lock is gone - there is no websocket field on the
serializer and nothing reads one - so DRF has been silently dropping the
key. Removing it also drops the store's only isSynced reader.
The service worker still wrote an entry to a doc-content table keyed on
documents/{id}/content/, an endpoint that no longer exists. Nothing ever
read it back: handlerDidErrorRead only ever asks for doc-list and
doc-item. The table is dropped on the next upgrade so it does not linger
in browsers that already have it.
This also clears the five standing typescript errors in the repository,
which were all stale doc-content literals in the tests for the code
being removed.
Signed-off-by: Kevin Jahns <kevin.jahns@protonmail.com>
Some networks refuse a websocket upgrade - corporate proxies, captive
portals - and a browser is told nothing more than "the connection
closed", so those users could not edit at all. The editor now runs a
second transport next to the socket, polling the collaboration server's
REST api on the same room, with the same session cookie and the same
authorization, and only while the socket is down. Local changes go out
about a second after the last keystroke and remote ones arrive within
ten seconds, so editing works with visibly more latency rather than not
at all. The socket keeps being retried underneath, so a client that fell
back during an outage returns to it on its own, and nothing is lost in
either direction - both transports publish from the same document.
This makes /collaboration/ydoc/ a route browsers call, so
COLLABORATION_SERVER_ORIGIN is now handed to yhub as its cors
configuration and gates the http routes as well as the websocket.
Signed-off-by: Kevin Jahns <kevin.jahns@protonmail.com>
The yhub server returns custom status code when the websocket is not
accessible, like 4401 when an access is removed and 4404 when a document
is deleted. the websocket client now use these custom status code to
stop reconnection forever.
We remove the code related to the content GET and
PATCH endpoints, as they are no longer used in the
codebase. The yhub server will handle the content
management directly, providing the content and
managing the updates. This change simplifies the code
and reduces the complexity of the frontend application.
We will need to reimplement the saving mechanism
in the service worker when we are offline.
Let's wait that the service is fully developed
on the yhub side before we implement this feature.
We will not block anymore the users not connected
to the collaboration server from editing the document,
we will have an HTTP fallback instead, so we can
remove the "can-edit" mechanism and the related code.
The /api/convert route no longer accepts the Y_PROVIDER_API_KEY shared
secret. It now verifies the admin JWT signed by Django against the
JWKS published on its /api/v1.0/jwks endpoint.
Add POST /collaboration/reset-connections/v1/{org}/{docid} (optional
X-User-Id header) to yhub-server. It distributes yhub recheckAuth: every
server re-runs the access check per matching connection and closes only
those whose access actually changed (close code 4401), so unaffected
clients see no reconnect churn. The endpoint authenticates with the
RS256 admin JWT issued by JWTService, verified against the backend JWKS
(new jose dependency); the admin token acts as the "system" user and is
the only principal granted the reset-connections access purpose. The
backend does not trigger it on permission changes yet - that wiring
comes separately, now that CollaborationService is gone.
yhub is upgraded to 0.4.0 and serves every route under the
/collaboration/ prefix (server.apiPrefix): the websocket moves to
/collaboration/ws/v1/docs, and the built-in document apis are meant to
be publicly exposed alongside it, with reset-connections as the one
backend-internal exception.
Also harden websocket auth: fail closed when the backend errors (only a
genuine 401/403 falls back to the anonymous identity, so a signed-in
editor can never hide from a targeted recheck under an anon userid) and
tolerate small clock skew when verifying the cached admin token.
Signed-off-by: Kevin Jahns <kevin.jahns@protonmail.com>
Reset the background when Backspace converts a callout to a paragraph.
Preserve content, alignment, regular text deletion, and undo behavior.
Fixes#2052
Signed-off-by: Manixhor <manigururam@hotmail.com>
Export Markdown as a ZIP containing the document and same-origin media.
Normalize filenames and restore the export UI after asynchronous failures.
Cover media packaging, modal behavior, filenames, and the browser flow.
Signed-off-by: Gokul Krishna <gokul.06krishna@gmail.com>
Ctrl+Alt+P (Cmd+Option+P on macOS) opens the current document in
presentation mode, saving two clicks through the document menu.
Signed-off-by: Anveet Pal <anveetpal12@gmail.com>
We can now choose to duplicate documents along with
their subdocuments. A confirmation modal will now
appear to let the user choose whether to include
subdocuments in the duplication, only if the document
has subdocuments.
A toast notification will inform the user and
give the possibility to undo the duplication if
needed.
Update lightly the ui to match the new design mockups,
to fit with what was proposed for the duplicate subdocs
feature.
It updates:
- modal closing position
- checkbox style
- toast style
- create a ButtonLink component, a wrapper above
the ui-kit component to fit the Next.js routing system.
We fixed the redirect behavior after deleting a
document to ensure the user stays on the correct page
after deleting a document.
We added a test to avoid regression in the redirect
behavior.
useToastProvider()'s `toast` function is recreated by the provider
every time any toast is shown anywhere in the app. useUploadFile
listed it as a dependency of `uploadFile`, which is itself a
dependency of useCreateBlockNote, so an unrelated toast (e.g. "Link
copied!") recreated `uploadFile` and made BlockNote rebuild the whole
editor instance, resetting the scroll position to the top of the
document.
Added useToast, a drop-in wrapper around useToastProvider that keeps
`toast`'s identity stable behind a ref, and switched every call site
in the app to use it instead of the provider's hook directly.
Dropping a file larger than the allowed size showed a bare "unknown
error" in the editor. The proxy in front of the API cuts the request
and answers a 413 with an HTML body, so errorCauses threw while
parsing it as JSON and no cause ever reached the error panel.
The size limit the backend already enforces is now exposed by the
config endpoint, and the editor checks the file against it before
sending anything, with the same toast wording the document import
uses. errorCauses no longer throws on a body it cannot parse, and a
413 without a usable cause falls back to an explicit message, which
covers the instances whose proxy limit is lower than the application
one.
The size formatting duplicated in the import hook moved to a shared
util.
Signed-off-by: risk-alt <aldu6974@gmail.com>
$opt_in fired on every reconnect since opt_in_capturing() captures an
event by default, even though this call just re-enables tracking after
a network drop and isn't a real consent action. Also disable web
vitals capture, which fed a single low-value insight.
Added:
- 🔧(backend) fine tune redis cache options
- ✨(frontend) make the full last-update date available
- 💄(frontend) redesign email confirmation standalone page
Changed:
- ⬆️(backend) upgrade celery to version 5.6.3
- ⚡️(backend) stop using LEFT(value, LENGTH(path)) in sql queries
- 🚚(project) switch docspec image to ghcr.io/docspec/api
- 🚚(global) move favorite documents API endpoint
to `/documents/favorites/`
Fixed:
- 🐛(backend) skip session creation for the liveness probe
- 🐛(frontend) preserve page titles when adding an emoji
- 🐛(frontend) scroll to the linked block in read-only documents
- 🐛(frontend) hide the selection highlight on presenter images
- 🐛(y-provider) prevent process crash on malformed websocket frames
- 🐛(frontend) keep commented text sharp when printing to PDF
- 🐛(docker) pull minio images from quay.io
- ♿️(frontend) restore presenter focus trapping after share links
- 🐛(frontend) export any raster image supported by the browser to a PDF
BlockNoteReader (read-only docs) doesn't register the find & replace
tiptap extension. If the panel is left open while the active editor
switches to it -- e.g. a collaborative doc turning read-only after a
WebSocket disconnect -- calling into its commands threw
"commands.clearSearch is not a function".
useFindReplace now exposes whether the current editor actually
supports find & replace, and FindReplace closes the panel and renders
nothing when it doesn't, instead of crashing.
When a WebSocket connection is rejected for a missing Origin or cookies,
or hits a route with no matching handler, express-ws still completes the
upgrade handshake and only closes the socket afterwards. The `ws`
library keeps parsing incoming frames during the close handshake, which
can take up to 30 seconds, and no 'error' listener was attached to these
sockets in the meantime. A single malformed frame (e.g. reserved bits
set) made the parser emit an unhandled 'error' event, crashing the whole
process and taking down realtime collaboration for every connected user.
We now attach the error listener on every WebSocket as soon as it is
created, before any routing or middleware runs, so malformed frames are
logged instead of crashing the server.
Recent changes broke the way the titles were displayed
when a emoji was present. It was displayed on 2
lines instead of a single line.
We fixed the CSS to ensure that titles with emojis
are displayed on a single line.
We improved the way the underline is displayed with
interlinking blocks.
Moving a doc via drag-and-drop already applies the move locally through
`treeData.handleMove`, but `useMoveDoc`'s `onSuccess` also
invalidated the `KEY_DOC_TREE` query, which `useDocTree`
reacts to by nulling `treeContext.root` and forcing the whole tree to
refetch and remount. Add a `skipTreeInvalidation`
option so the drag-and-drop handler can skip that invalidation
and rely on its own local update, while other callers (e.g. the
move modal) keep reloading the tree as before.
Gecko cannot express a blended run in PDF, so it falls back to a bitmap of that
run: every commented sentence came out of Print as a 72 dpi image while the rest
of the page stayed text. The print stylesheet already hid the comment highlight,
but only its background and border, so mix-blend-mode stayed and that is what
forces the fallback.
Measured on the engine the report came from, printing the same page twice:
with the current rule the commented run is not extractable and the file carries
an image plus its alpha mask, with mix-blend-mode neutralised it is text again
and the file carries no image at all.
Signed-off-by: tanguy chenier <tanguychenier@gmail.com>
Keep the relative timestamp in the document header while exposing the
localized full date through the existing tooltip on hover and keyboard focus.
Signed-off-by: fch-aa <21101725+fch-aa@users.noreply.github.com>
The ws library emits an unhandled 'error' event when a client sends a
frame with unexpected RSV bits (e.g. permessage-deflate mismatch),
which was crashing the whole y-provider process since no listener was
attached to the socket. Add an error listener to log and drop the
offending connection instead.
We added a new webp image to the e2e tests and updated the export
tests to include this new image format.
This ensures that the export functionality correctly
handles webp images, maintaining compatibility and
performance across different image formats.
We increase throttles, to be sure that the e2e tests
don't hit them.
In order to ensure that complex PNG images are
exported correctly, we have added an end-to-end
test that verifies the export functionality.
This test will help catch any regressions related
to image exports in future updates.
Signed-off-by: Mathieu Agopian <mathieu@agopian.info>
WebP format isn't supported by react-pdf/renderer and so wasn't exported
properly, and some PNG images were also not exporting.
First drawing those raster images to a canvas and providing a dataURL to
react-pdf/renderer fixes those two bugs at once.
Signed-off-by: Mathieu Agopian <mathieu@agopian.info>