Commit Graph

2398 Commits

Author SHA1 Message Date
davd-gzl aafbc752d5 🔒️(ci) pin every action to a full commit hash
A tag and a branch both move, so actions/checkout@v6 and
numerique-gouv/action-trivy-cache@main ran whatever the owner had last
pushed. Each of the 65 uses now names a 40-character commit, with the
version it resolved to in a trailing comment.

dependabot.yml keeps the hash and that comment moving together.
2026-08-31 19:03:27 +02:00
davd-gzl a24100aceb 🔒️(ci) harden the remaining fetches in the workflow
gitlint-core keeps the linter at 0.19.1, which the wheels-only pin was
resolving down to 0.18.0 through an sdist-only sh. --ignore-scripts
stops three npm ci, one yarn install and one npm install -g running
the scripts of what they fetch, and yarn is pinned to 1.22.22. curl
holds the dockerize download and its redirects to https.
2026-08-31 19:03:27 +02:00
davd-gzl 9e2383a341 🔒️(ci) install dependencies without running their setup code
A package could run arbitrary code on the runner while installing,
and the versions were resolved rather than taken from the pins.
The two pip calls now take wheels only, and uv run no longer
resolves an environment of its own.
2026-08-31 19:03:27 +02:00
moustique82 80d37595ad (frontend) expose publish permissions in MediaStateObserver
The component exposes the local microphone and camera state so external
tools automating the frontend can read it. It does not expose whether
publication is allowed, so such a tool cannot tell a muted microphone from
one it is not permitted to unmute, and ends up offering a control that
silently does nothing.

Expose canPublishMicrophone and canPublishCamera in the event detail and as
data attributes, reusing the useCanPublishTrack hook that already gates the
web client controls. The permissions are part of the effect dependencies so
a mid-meeting permission change emits the event.
2026-08-31 16:55:36 +02:00
snyk-bot 2daa668075 ⬆️(addons) upgrade core-js from 3.49.0 to 3.50.0
Snyk has created this PR to upgrade core-js from 3.49.0 to 3.50.0.

See this package in npm:
core-js

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/af693e79-8c43-4c09-ab65-60580515c9e8?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-31 16:43:41 +02:00
Cyril a1e7978348 ️(frontend) announce Escape close hint on side panels
Show "(Escape)" in close tooltip, add aria-describedby for SR keyboard hint.
2026-08-31 15:57:59 +02:00
Cyril 4fa044fa3e ️(frontend) close side panel with Escape key
useEscapeToClose: close panel on Escape, restore focus, let chat input bubble
2026-08-31 15:57:59 +02:00
leo 2c5dd151f1 ♻️(backend) factorize s3 client creation in utils
Factorize s3 client creation in utils for code simplification.
2026-08-31 15:44:38 +02:00
leo a33e35111c ♻️(devex) update Makefile lint targets and harmonize service naming
The make lint target did not cover the summary and agents components. Update
the linting workflow to include both services and harmonize Makefile target
names. Harmonize Docker compose user declarations.
2026-08-31 14:52:10 +02:00
snyk-bot 02714c869a ⬆️(frontend) upgrade @fontsource/opendyslexic from 5.2.5 to 5.3.0
Snyk has created this PR to upgrade @fontsource/opendyslexic from 5.2.5 to 5.3.0.

See this package in npm:
@fontsource/opendyslexic

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-31 14:37:44 +02:00
snyk-bot 826cfe0c62 ⬆️(frontend) upgrade @fontsource-variable/lexend from 5.2.11 to 5.3.0
Snyk has created this PR to upgrade @fontsource-variable/lexend from 5.2.11 to 5.3.0.

See this package in npm:
@fontsource-variable/lexend

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-31 14:10:02 +02:00
Louis-Jean Teitelbaum ab62ae71ea 🐛(frontend) fix chat text-area bug
Whenever a character was typed, the caret would jump
to the end of the textarea. Fixes #1656.
2026-08-31 13:59:39 +02:00
Miguel Victoria 3991235903 More natural language on interface 2026-08-31 13:59:21 +02:00
Miguel Victoria d2a74a20fd chore: improve backend translations 2026-08-31 13:59:21 +02:00
Miguel Victoria 0446d1e824 update comment lines on django.po files 2026-08-31 13:59:21 +02:00
Villaquiranm a20a0a6b38 🌐(i18n) add Spanish language support
Add Spanish to the language selection system on both trees, with 872
frontend phrases and 145 backend ones translated from the French source.

The frontend to backend language map gains it too, so a Spanish browser
does not write an empty language to the account on every load.
2026-08-31 13:59:21 +02:00
snyk-bot 564b3dc595 ⬆️(frontend) upgrade posthog-js from 1.409.5 to 1.414.0
Snyk has created this PR to upgrade posthog-js from 1.409.5 to 1.414.0.

See this package in npm:
posthog-js

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-31 13:56:44 +02:00
leo 0a0cdae896 (agent) support Voxtral realtime as inference engine
The Kyutai open-source model turned out not to be production-ready:
it caused disruptions in the production environment, especially on
long-running meeting sessions.

Switch to the Voxtral realtime model, which looks like a
credible competitor and behaves much better in our setup.

For now, the code handling the Voxtral realtime API lives directly
in the project. It could be extracted into an open-source package
later.

See PR #1277 for the full details of the implementation, proposed
by @cameldev.
2026-08-28 12:18:52 +02:00
leo c7e3168ba3 🔥(backend) remove the S3 storage-event webhook for recordings
Recordings used to be finalized by an inbound notifications sent by
S3. This tied the recording lifecycle to bucket notifications, adding
complexity and dependency to limited S3 services.

The LiveKit egress_ended webhook, added as a fallback in aee1847, does
the same job without any object-storage dependency. Make it the only
mechanism: RecordingEventsService.handle_complete is now called on
EGRESS_COMPLETE / EGRESS_LIMIT_REACHED unconditionally, instead of only
when RECORDING_STORAGE_EVENT_ENABLE is False. Remove the storage-event
path entirely.
2026-08-27 23:09:48 +02:00
lebaudantoine f1d3799434 🔖(minor) bump release to 1.29.0 v1.29.0 2026-08-25 23:22:29 +02:00
lebaudantoine e59aaaa998 📝(changelog) fix a minor changelog issue
Wrongly added to an old section during a rebase.
2026-08-25 23:14:16 +02:00
lebaudantoine 76a24d4787 ️(backend) replace blocking Redis KEYS with cursor-based SCAN
`cache.keys()` runs Redis `KEYS`, a full-keyspace scan on Redis's
single thread that blocks everything else, including session reads
in the same cache. Its cost scales with total keys, not matches,
and some managed providers disable `KEYS` entirely.

The trusted-lobby feature made this urgent: the waiting-list
endpoint scanned on every poll, and its polling audience grows from
a few admins to potentially every authenticated participant.

Switch to cursor-based `SCAN` via two `core.utils` helpers, deleting
in bounded batches so cleanup of a large room cannot block either.
A single seam also lets us forbid raw `cache.keys()` going forward.

`SCAN` still iterates the keyspace incrementally on the polled
path. If monitoring flags it, the follow-up is a per-room set
index — out of scope here since it changes the lobby storage model.
2026-08-25 22:48:47 +02:00
lebaudantoine 943b81676b (frontend) let authenticated users manage the lobby on trusted rooms
Frontend counterpart of the trusted-lobby backend feature: on
`trusted` rooms, any authenticated participant sees the waiting
notification and can accept or deny entry requests, not only admins
and owners.

Gating moves from role to capability: `useCanManageLobby` mirrors
the backend permission and derives from `useRoomData()`. Room
metadata is already synced into the query cache, so an access-level
change mid-meeting recomputes the capability on every client with no
new sync mechanism. It is only a UI gate; the backend re-checks
everything per request and fails closed.

Fetching moves into a single room-level `LobbyProvider`: the hook
was previously instantiated by two components and only worked
because React Query deduplicated their queries. The provider owns
one query and an explicit state machine - ways in (connection
established, ParticipantWaiting broadcast, panel opened, rights
regained while the panel is open) all arm and fetch; ways out
(rights lost, server 401/403) disarm and clear the cached list so
nothing stale can render.

Polling is tiered by audience since managers grow from a few admins
to potentially the whole room: 1s when acting (panel open),
10s when the notification is shown, and zero when the list is empty -
decided in the refetchInterval callback because structural sharing
suppresses data-keyed effects on identical empty responses. A quiet
room costs nothing; fetches are triggered by uncorrelated human
events, never synchronized across the room (the rights-regained
trigger is panel-gated for this reason).
2026-08-25 22:48:47 +02:00
lebaudantoine 7369379106 (backend) let any authenticated user manage the lobby on trusted rooms
On rooms with the `trusted` access level, any authenticated user
connected to the meeting can now manage the lobby. Requested by
several organizations, and a step toward generalized lobby
management once hubs and groups land (same organization only).

Being authenticated is not enough to grant the capability: a
`trusted` room means "trusted to join", not "trusted to decide who
else joins from outside the call". The new `CanManageLobby`
permission therefore also requires the requester to be currently
connected to the meeting, verified against LiveKit and failing
closed, like `IsPresentInMeeting`. The access level itself is never
cached and always read fresh, so an owner switching the room back to
`restricted` revokes the capability on the very next request - the
one guarantee we did not want to trade for performance.

Performance is traded elsewhere: the waiting list is polled by every
lobby manager, and on a trusted room that audience grows from a few
admins to potentially the whole meeting. Hitting LiveKit once per
poll per participant would not survive that fan-out, so presence is
memoized in Redis (`PresenceCache`, `PRESENCE_CACHE_TIMEOUT`, 1h).
Entries are created lazily because only the minority of participants
who actually manage a lobby ever need one, and only positive answers
are cached because a sticky negative would lock out someone joining
right after a miss for the whole TTL. Eager invalidation on
`participant_left`, `room_finished` and admin kick keeps the cache
honest; the TTL is the safety net when an event is lost, and its
value bounds how long a departed participant could still act.

Trade-offs in this v0:

* `PRESENCE_CLEAR_ON_PARTICIPANT_LEFT` gates the eager invalidation
  on `participant_left`: its cost is one Redis DELETE per departure,
  for every departure, so we want to be able to measure it in
  production and turn it off independently of the feature. When
  disabled, invalidation relies on `room_finished` and the TTL only,
  widening the stale window above.
* This can put non-trivial pressure on the cache at scale; the
  rollout will need to be monitored closely.
* The `participant_left` webhook must be enabled in the LiveKit
  deployment, otherwise eager invalidation silently degrades to the
  TTL-only behavior.
2026-08-25 22:48:47 +02:00
lebaudantoine c02d54b6ff ️(frontend) apply frugal constraint to the active meeting audio track
Apply the `VOICE_AUDIO_CONSTRAINTS` to the audio track used during
the active meeting to reduce bandwidth usage.

* Originally proposed by trummerschlunk to reduce bandwidth, but
  previously restricted to the join screen preview.
* Backport the standard voice constraints (48 kHz sample rate,
  mono channel, 16-bit sample size) to the active call session, as
  requested by the BBBA team.
2026-08-25 22:33:42 +02:00
Florent Chehab cec2eb5a10 (summary) add hostname to analytics properties
This helps track down what was the source of events.
This can be usefull when checking perf of different workers for instance.
2026-08-25 14:48:06 +02:00
snyk-bot 2858d141f4 ⬆️(frontend) upgrade posthog-js from 1.404.1 to 1.409.5
Snyk has created this PR to upgrade posthog-js from 1.404.1 to 1.409.5.

See this package in npm:
posthog-js

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 16:15:15 +02:00
snyk-bot f10429581b ⬆️(frontend) upgrade @pandacss/preset-panda from 1.11.3 to 1.12.0
Snyk has created this PR to upgrade @pandacss/preset-panda from 1.11.3 to 1.12.0.

See this package in npm:
@pandacss/preset-panda

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 15:58:10 +02:00
snyk-bot b3369cddf7 ⬆️(frontend) upgrade @tanstack/react-query from 5.101.1 to 5.101.4
Snyk has created this PR to upgrade @tanstack/react-query from 5.101.1 to 5.101.4.

See this package in npm:
@tanstack/react-query

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 15:50:19 +02:00
snyk-bot cfffadc780 ⬆️(frontend) upgrade i18next-resources-to-backend from 1.2.1 to 1.2.3
Snyk has created this PR to upgrade i18next-resources-to-backend from 1.2.1 to 1.2.3.

See this package in npm:
i18next-resources-to-backend

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 15:41:16 +02:00
snyk-bot 4ae31b3297 ⬆️(frontend) upgrade @fontsource-variable/atkinson-hyperlegible-next
Snyk has created this PR to upgrade @fontsource-variable/atkinson-hyperlegible-next from 5.2.6 to 5.3.0.

See this package in npm:
@fontsource-variable/atkinson-hyperlegible-next

See this project in Snyk:
https://app.eu.snyk.io/org/lasuite-dinum-default/project/96ea03d8-8d09-493d-86bf-363f274e129e?utm_source=github&utm_medium=referral&page=upgrade-pr
2026-08-24 15:20:49 +02:00
lebaudantoine 954991c7c3 📱(frontend) improve feedback screen responsiveness on mobile
Tighten the feedback screen layout on mobile viewports so it fits
comfortably on small phone screens and reads naturally without
horizontal scroll or cramped controls.
2026-08-24 14:51:07 +02:00
lebaudantoine 6e2a7f0ca6 📱(frontend) stack idle modal buttons in a column on mobile
Wrap the buttons in the idle modal so they stack vertically on
mobile viewports.

The horizontal layout was cramped on small screens; a column layout
gives each button a comfortable touch target and reads more
naturally on narrow displays.
2026-08-24 14:51:07 +02:00
lebaudantoine 24404e4ea2 📱(frontend) collapse mobile control bar items on narrow viewports
Apply the same approach as the PiP screen to the mobile control
bar: make sure it never overflows on small phone screens by
collapsing some controls into the overflow menu when there is not
enough horizontal room.
2026-08-24 14:51:07 +02:00
lebaudantoine f18d784615 🔖(minor) bump release to 1.28.0 v1.28.0 2026-08-24 11:32:06 +02:00
lebaudantoine 1bfe6b8977 🔇(frontend) suppress leaked WebSocket error events from livekit-client
livekit-client leaks the raw WebSocket error Event as an unhandled
rejection when the signal WebSocket errors after connect. This is
mostly seen on Firefox and coincides with signal reconnects.

The event carries zero diagnostic content — the close reason is
already logged by the SDK — so it only adds noise to error
tracking.

Filter it out from our reporting.

Upstream issue: https://github.com/livekit/client-sdk-js/issues/2062
2026-08-23 18:12:18 +02:00
lebaudantoine 84845709d0 🐛(frontend) make the device-in-use logic race-free
The device-in-use logic could race when multiple detection events
fired close together (e.g. rapid mic/cam toggles or several devices
becoming busy at once), leading to inconsistent store state.

Refactor the flow so all updates go through a serialized path,
removing the race conditions and keeping the in-use state
consistent regardless of event ordering.
2026-08-23 17:40:01 +02:00
lebaudantoine e000377b5c ♻️(frontend) track device-in-use state by id instead of by kind
Refactor the device-in-use handling to key state by device id
instead of only by kind (microphone or camera).

On computers with several devices of the same kind, keying by kind
meant that one device being in use marked the whole kind as busy,
even when the user could still use another device. Tracking per id
lets the UI and logic distinguish between devices correctly.

The store is updated accordingly so that per-device state is stored
and read consistently across the app.
2026-08-23 17:40:01 +02:00
lebaudantoine a9fa3eb4ba 🐛(frontend) treat "Timeout starting source" AbortError as device-in-use
Also consider `AbortError` with a message like "Timeout starting
video/audio source" as an "already in use" device error.

This can happen for other reasons in theory, but in practice most
occurrences are caused by another application still holding the
camera or microphone.

Route it through the existing device-in-use handling so users get
the same clear explanation as with the standard error, instead of a
generic failure.
2026-08-23 17:40:01 +02:00
lebaudantoine 2ec3f54532 🐛(frontend) handle Firefox/Windows AbortError on device start
Some versions of Firefox on Windows do not raise the
`NotReadableError` that LiveKit expects when the camera or
microphone fails to start. Instead, they surface an `AbortError`
with a message explaining the browser could not start the video or
microphone input.

This case was observed in PostHog error tracking and was not
handled, so users hit an unhelpful failure state.

Detect that specific `AbortError` and route it through the same
device-in-use / not-readable handling as the standard error, so
users get a clear explanation.
2026-08-23 17:40:01 +02:00
lebaudantoine d723c14d84 🐛(frontend) handle device-in-use errors on Chrome / Windows 10
On Chrome and Windows 10, when the camera or microphone is already
in use by another application, the browser rejects
`getUserMedia`. Without dedicated handling, users just saw their
camera or microphone not turning on, without any explanation.

Detect this specific failure and surface a clear message to the
user, so they understand another application is holding the device
and know what to do about it.
2026-08-23 17:40:01 +02:00
lebaudantoine e5f0b1c202 🐛(frontend) fix joined notification tile no longer rendering properly
The toast is enqueued on `ParticipantConnected`, which livekit-client
fires before the participant's track publications exist. At that
point `getTrackPublication(Camera)` is `undefined`, and the track
ref used by the toast is frozen that way — the toast never
re-subscribes to the participant.

Downstream effects:

* LiveKit's `useIsMuted` initializes to `false` when there is no
  publication, so the tile first paints with
  `data-lk-video-muted="false"`, which the stock CSS maps to
  placeholder `opacity: 0` — a blank box.
* Its effect then subscribes to `mutedObserver`, which defaults to
  `true` for the same situation, triggering a second render and
  only then starting the 200 ms fade-in. That render-effect-render
  transition is the visible lag behind the text.
* Because the track ref never updates, no `VideoTrack` ever mounts.
  When the camera is later subscribed, the placeholder fades out
  again, leaving the tile empty.

Re-derive the track ref inside the toast when the participant's
publications become available, so `useIsMuted` sees the real state
from the start and the tile renders the video (or a stable
placeholder) instead of a blank box.
2026-08-21 22:55:28 +02:00
lebaudantoine 9e0d57a8c6 🐛(frontend) hoist mute confirmation dialog to VideoConference level
`MuteButton` owned the confirmation dialog state locally. On the
participant tile, the button lives inside `FadeOverlay`, which
conditionally mounts its children based on tile mouse activity
(3 s idle timeout). Once the user moved the pointer onto the
react-aria portal, mouse events on the tile stopped, the idle timer
expired, `FadeOverlay` unmounted `MuteButton`, and the dialog was
destroyed with it — hence the "closes randomly" behavior.

Render the dialog once at the VideoConference level via a shared
`MuteAlertDialogProvider`, so its lifetime is independent from any
button that opens it.
2026-08-21 22:55:28 +02:00
lebaudantoine 7ba0803b71 💄(frontend) increase the blur intensity
Bump the blur strength applied to virtual backgrounds so it obscures
the background more effectively.

Requested by users.
2026-08-21 22:55:28 +02:00
lebaudantoine beacfc3d3f 🐛(frontend) stop init_virtual_background from firing on blur updates
A regression introduced with the custom virtual background feature
(16daf7b8, March 26): every blur init on Firefox, and every update
call, was going through `init_virtual_background`, which raised an
error because there is no virtual background to initialize in that
code path.

The existing guard was incorrect. Replace it with an early return,
so `init_virtual_background` is only executed when there is actually
a virtual background to initialize.

This does not fix the other virtual background issues that currently
prevent some users from activating their camera; those will be
addressed separately.
2026-08-21 22:55:28 +02:00
lebaudantoine 52e5d99e83 📈(frontend) track errors when starting or stopping a recording
Send an analytics event whenever starting or stopping a recording
fails, so we can monitor how often it happens.

It also gives support the context needed to understand what went
wrong when inspecting a user's session.
2026-08-21 22:55:28 +02:00
lebaudantoine 15ca2b41b4 🐛(frontend) use state instead of a ref for MoreControls container
After the recent refactoring, `MoreControls` only renders once. On
that first render, the container ref is `null`, and when it later
gets a reference to the div, the ref update does not trigger a
re-render.

As a result, the additional controls were never showing up.

Switch from a ref to a state to track the container element. State
updates do trigger a re-render, so the controls now show as
expected once the container is available.
2026-08-21 22:55:28 +02:00
lebaudantoine e34f3dd219 🐛(frontend) treat client-initiated connect aborts as events
`connect()` calls can be aborted by a `disconnect()` before the
join completes — typically when the user leaves, refreshes,
navigates away early, or when the component remounts. This is
expected behavior, not a failure.

Stop reporting these as errors. Track them as analytics events
instead, so we can still monitor their volume without polluting
error dashboards.

Volume is relatively low, but keeping visibility helps troubleshoot
users who complain about difficulty connecting to a room, and could
also flag a component that is re-rendering and killing the
connection.
2026-08-21 22:55:28 +02:00
lebaudantoine feb573551f 💡(frontend) warn in vite config on MediaPipe asset/track-processor drift
Add a build-time warning in the Vite config that fires when the
MediaPipe assets copied by `vite-plugin-static-copy` fall out of
sync with the version used by `@livekit/track-processors`.

This catches at build time the kind of drift that would otherwise
only surface at runtime as broken virtual backgrounds.
2026-08-21 18:09:31 +02:00
lebaudantoine 1d0a0cc637 ⬆️(mail) upgrade Node image for mails-install to align with the frontend
Node 18 is now legacy, and running `make mails-install` was failing
with a "bad engine" error against the current image.

Bump the Node image used for `mails-install` to a more recent
version, aligned with the one used by the frontend, so the make
target runs cleanly again.

Note: the Alpine variant cannot be used here, as `bash` is required
to build the mail templates.
2026-08-20 16:09:03 +02:00