Avoids mounting the button's hooks and rendering its logic for users who
are not admin or owner, which previously happened on every re-render
of the parent.
This commit introduces the compatibility with summary v2.
It tecnically doesn't break the compatibility with v1 as
v1 params are still sent. But we advise people using the
transcribe feature in their own deployments to adapt to the
new v2 API, as this compatibility will be removed in a
future major version.
* RecordingStatusChoices now has
EXTERNAL_PROCESS_SUCCESSFUL
& EXTERNAL_PROCESS_FAILED
Values, which are changed by a new webhook that
can be called by the transcribe service.
This webhook is protected by its own bearer token.
* Title for the document is computed in visio,
* Tests are added / updated accordingly
Add react-aria 3.49.0 + react-stately 3.47.0 as direct deps and bump
react-aria-components to 1.18.0 so react-stately resolves to one version.
Fixes the nominal Timer type clash and missing @react-stately/toast
imports introduced by the React Aria v1.17 monopackage consolidation.
Ad blockers recently started blocking requests to our PostHog
feature flag API, leading to undesired behavior in the app.
Following PostHog's documentation, allow configuring a dedicated
domain for feature flags, isolated from the main PostHog domain.
Following internal feedback, rename the "Premium" wording to
"Advanced" across the transcription and recording sidepanels, so the
label no longer implies a paid tier.
When joining a meeting that already has many participants, new
participants are now muted by default.
This is an empirical change, not directly requested by users but
informed by user experience: a lot of people joining large meetings
arrive with their microphone and/or camera open, which can be
painful for the host, who otherwise has to mute everyone or ask
everyone to mute. Many of these participants are inattentive but
still noisy.
If you are joining a room that is already at a certain size, you are
probably not the one expected to speak; presenters typically join
among the very first participants.
In particularly large rooms, with more than 5 or 10 participants,
the entry notification sound can quickly feel spammy.
A configuration to disable it exists, but new users do not discover
it easily. The sound notification is most useful while waiting for
the first few participants to arrive; once a few people are in, the
meeting usually starts and the sound becomes more disruptive than
helpful.
The visual notification remains in place, so users are still aware
when newcomers join. Roll this out and check whether users find the
change helpful.
Required by some self-hosters who want to present a link to
participants that are guests only, without access to their SSO. For
example, a meeting between a citizen and a public servant where the
guest is known not to have an account.
Also useful when rendering the join page inside an iframe.
Several clients ran into issues with the silent login, leading to
redirections that were not appropriate for their use case.
Offer a URL parameter to control this behavior and disable silent
login when needed.
The noise-suppression processor is now imported on demand with a
dynamic import() instead of a top-level static import, so it lands in
its own code-split chunk rather than the main bundle.
Why this is necessary:
* @libreaudio/la-call is fully self-contained. It inlines *everything*
as JavaScript: two WASM binaries (SIMD and non-SIMD variants), the
Emscripten glue, the worklet processor source, and the noise model
plus its weights — the model is compiled into the .wasm, so we ship
effectively two copies of it.
* The WASM is inlined as numeric array literals (new Uint8Array([...])),
the least compact representation possible (~2-4 source chars/byte) and
not meaningfully minifiable. The result is a large module that also
can't be stream-compiled the way an external .wasm asset would be.
* A static import would pull all of that into the initial bundle,
inflating critical-path download size and lengthening build time
(parsing/minifying the big literal) — for a feature that's only used
when the user actually turns on noise suppression.
* Dynamic import() isolates the whole payload in a separate,
content-hashed, browser-cached chunk. The cost (chunk fetch + WASM
instantiation) becomes a one-time hit deferred to first activation,
and is fully off the page's initial load path.
Notes:
* The library self-bundles its AudioWorklet at runtime from a Blob URL
and inlines the WASM, so it needs no build-tool asset plumbing
(no ?worker&url / ?url, no Vite asset config). The dynamic import is
therefore the only splitting mechanism required.
* Audio processing still runs off the main thread on the AudioWorklet
path (desktop/most browsers); only the Android ScriptProcessor
fallback runs on the main thread. Import style does not affect this.
* To hide the first-activation latency, the chunk can be prefetched
(e.g. import() on idle or <link rel="modulepreload">) so it's warm
before the user enables suppression.
Replace the basic RNN noise processor with a more advanced audio
pipeline powered by Big Blue Better Audio (BBBA), a project
supported by the Prototype Fund.
The new WASM-based pipeline introduced by @falkTX and
@trummerschlunk adds:
- voice isolation
- high-pass filtering
- spectral balancing
- multiband compression
- low-pass filtering
This significantly improves overall audio quality and speech
clarity.
More information about the pipeline is available on the
trummerschlunk/BigBlueBetterAudio repo.
Voice isolation still relies on RNNNoise, a widely used deep
learning-based denoising model. Audio quality could be further
improved in the future if DeepFilterNet becomes usable directly
in the browser.
Their code has been released in an NPM package under GPL license.
Uninstall `vite-tsconfig-paths` as path resolution is now supported
natively by Vite's built-in configuration.
Remove the unused dependency and simplify the frontend tooling setup.
The upgrade introduced around 50 new linting errors. Fix the
low-hanging fruit and address straightforward violations.
Several of the new rules appear to target patterns intended for newer
React compiler capabilities. Since the project currently runs on
React 18 rather than React 19, disable these rules for now instead of
applying potentially inappropriate changes.
Follow-up work can address the new rules in a dedicated PR, potentially
alongside a future React version upgrade.
Removes Node.js type dependency from browser/React code by substituting
the non-portable `NodeJS.Timeout` type with the standard
`ReturnType<typeof setTimeout>` equivalent across all affected files.
Also replaces `process.env.NODE_ENV` in Icon.tsx with
`import.meta.env.MODE` for Vite compatibility.
With the addition of the ANALYSING state
files could be accessed in the short time they
were in that state.
We now require files to be in ready.
Also adds missing frontend types (no impact).
Manually upgrade the frontend codebase to ESLint 9.
Update the linting configuration and related code where required to
maintain compatibility with the new major version.
Avoid stacking too many components in route/home. Keep only the
responsibility of orchestration and layout in the home route, and
move stateful components to their appropriate folder.
The homepage previously relied on the userChoices store, which loads
the persisted user choices from localStorage. However, this store is
widely used in the room feature, so code splitting ended up loading
the chunk containing the userChoices store at the initial render.
That chunk was bundled with unrelated parts that proved to be heavy.
Switch to a more straightforward approach reading the cached username
and verify the bundle output + intial loading.
Saves a few hundred ko on the initial load, now bundled in another
chunk that is loaded only when entering a room.
Material icons (and Symbols, the most recent ones from Google
Material) were initially adopted to align with the UI kit. Before
that, we relied on Remixicon, which loads only the icons used and
totals 40ko for the whole library.
To benefit from Material icons, the implementation matched the UI
kit, which uses two fonts: 150ko and 750ko. Unlike the UI kit, the
fonts were preloaded to prevent icon render blinks. On products using
UI kit, the fonts are loaded the first time an icon renders,
and because they are heavy, the icon swap is visible to the user.
Icons are replaced by their text label in the meantime, which also
caused screen-reader vocalization or i18n issues that had to be mitigated.
Preloading the fonts was a quick win that worked fine on high-speed
connections where fonts get loaded fast then cached. However, while
optimizing LCP for users on poor connections (a separate concern that
already affects videoconference joining), preloading proved harmful:
it stole network bandwidth at the most critical moment,
when the main JS chunk was loading.
Switch to a frugal approach: import only the SVG icons actually
needed from Material, treated as components so they are tree-shaken
and customizable (color, etc.). Icons do not change often, so the DX
remains good. The UI kit also supports custom icons not available in
the font, so this approach lets us define them and works like a
charm.
Removal of Remixicon is planned in a follow-up PR.
It save user loading almost 1Mo of assets for few icons.
posthog-js was bundled in the main chunk. Loading it dynamically saves
200ko on the initial load and around 4s of loading time on slow 4G
connections.
PostHog, and analytics in general, should not block the initial
rendering. The risk is that some feature-flagged features may not be
instantaneously available to the user, but for most users on
high-speed connections this will be imperceptible.
Other places in the code rely on a direct import from posthog, I only
verified the delay import of posthog for the home page, and did
not for the /room route. I'm pretty sure there is room for
improvements on other parts of the app.
The Valtio actions on the store were initially defined inside a hook,
which was a bad idea: it does not follow Valtio's recommendation of
defining actions at the module level, and the function definitions
were re-created every time the hook re-rendered, which happened on
every state update.
These action has nothing related to React.
Additionally, the snapshot should be used more directly so Valtio can
understand and optimize which parts of the proxy are of interest to
the snapshot being made.
Use the Python port of Google's phone number library on the backend
instead of the JS one on the client. Saves 140Kb of unnecessary JS
and avoids a complex dynamic import that would have been required to
optimize loading.
The transformation is static: the phone number lives in the Django
settings, so the backend can format it once and pass the result to
the client. This avoids every client loading the 140Kb library and
re-computing the same information.
Moreover, within a single client, the transformation was previously
re-computed several times during a webapp lifecycle.