Add guest meeting support and improve LiveKit integration#15
Draft
ArtyomSavchenko wants to merge 54 commits into
Draft
Add guest meeting support and improve LiveKit integration#15ArtyomSavchenko wants to merge 54 commits into
ArtyomSavchenko wants to merge 54 commits into
Conversation
Port of the virtual-office rework onto Platform-Collective/develop. Adaptations for our newer upstream base: - Dropped whisper/transcription-entangled ai-bot changes (transcription/*, transcriptions.ts, controller.ts, workspace/*) — those depend on the excluded "Towards Love whisper" commit and are out of scope here. - Grafted the new REST v1 doc-ops API (create/addCollection/update/remove/ createMixin/updateMixin) onto our refactored api-client rest client and pods/server rpc, since services/love now depends on it. - Kept our cockroach dev docker-compose and hardcoreeng image naming. (cherry picked from commit e6287f96d5fadd78eb00885ce94e911beaf03ee4)
Port of the login-styled guest meeting entry, adapted to avoid the fork's intabia-branded login-theme rework (9066f3b49d, out of scope). Adaptations: - Added a minimal UNBRANDED login-resources theme subsystem (theme.ts with a single 'huly' theme, no IntabiaIcon/GradiantBack/intabia.scss) so LoginAppBase and the guest components compile. - Kept our own LoginApp/Form pages; merged only the needed Form.svelte improvements (optional caption, proceedDisabled) rather than the fork's restyle. - Brought in LoginAppBase, AuthLikeForm, internal/Label from the fork and exported them; dropped the branded internals (FormButton/StylishEdit/EditBox come from the un-ported rework and aren't needed by the guest UI). - Added login.metadata.LoginTheme. - Renamed love GuestApp -> GuestMeetingApp and moved guest components under components/guest/, per the fork. (cherry picked from commit 503a17d496a43f6ebcc7f23e416fe6a978d86501)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 0cfa258399efb5c508eac9713af8d75a15bcd00f)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit abc690fa6f768bd4c5a0e2d744dcbeeb99ecf163)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit de04dd4ca200434fb85624791ed12e8c57a21c81)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit f0b1ba58d5521f3d6460b66e1763713dc6b5d1ee)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 753adaf1edd5be17920a1adc646e113c96001036)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 0e94dd5da307237e2c73b5fea8f6933b3d7a4168)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 145452d5e9cefaa26ddab85eb3a797c3ddcc8d2f)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 45df42eeabdda9f2d87dfa5f821d38cd095618f3)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 343079b057fe11127b83f33e3826160bccec9c6d)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 6aa823b770c1368056f6037168fac27c6f75824a)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 33cd55c1f34bb8d9670bb9d24320bf7bf25b3fc9)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 173792d87f978cc4bf2981427deb54666fb273d9)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 3c920dd4c4387375de0e90afbf323e4cefb4346b)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 52b7b1ed73311eef984f97d0d1c0e0590f5c4939)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit ae2086d8df321a1f88d9217c9a4f9378e4ab7277)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 01b2086a4d08bf5840f215d154604a3ed521d7dd)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 7b515547e76fa9c83d8f12b32816db14e8f3fd36)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit de2e9adb795af318c0b2c580def7c466fdce104e)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit cb778ae9807e8660be75fdbae1ce15d7ca5e865b)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit e4c93bfaa80e5e14d9bb3a0c8f075eedb627e0f3)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 79f07187e03abffd09f26f086c1baa62a4812238)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit d6f9350daf62d5ac9a77f62f36ccb1a88446cdfd)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit b71e9dc06052da6a9826a0e4b9398a62f8adba9a)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 662d376d325798a75dc9e1820945f764767389f3)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 3e0184102581cba3eaa01ad077cb21bfbe78ae79)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 810ce23d14bac61f1d40dccfadbedd60fe88ef60)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 144ccb55ee8d0afc47198d4f18519c9e50e8f071)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit b83f7f6b1e344ee03d940ff46e74a79023430cc5)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit b72027701331b4b9a4d822b5eb1cc54e7bdd56b4)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 17bb3091a9183fe637ed373a863a2c8407e8747b)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit c32ca91af901e3ffefad6970d7eb2674b9f882b4)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 951ec80270f540cb933de8ba23d3588089082143)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 5a383e356cfeff7b69fe7190af3624a6d445b558)
* FND-158 Changing individual meeting type to Video * FND-158 Bump version (cherry picked from commit b773d93cb0035b140c9c5be3c279f5b061903bee)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit 13faab7e2aa53c613b8aedabbc787c097642230b)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit e375a3bdcce9a542ad09a1e1c4ad08f58c0bfc2f)
(cherry picked from commit 192357254c734eaf2ce65541ee6ef30872068336)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> (cherry picked from commit cc4a885b5eb8c09f5d20f328f92a3b5cbeb23cfe)
Replace the Cyrillic 'С' (U+0421) in 'videoPopupСontainer' with Latin 'C' (videoPopupContainer) across the container-query CSS, per the port plan §7.
A leftover '>>>>>>> 662d376d32' marker slipped through when resolving the guest-identity conflict; remove it so api-client compiles.
Regenerated via 'rush update' after the office/video port added deps to services/love, love-resources, and server-plugins/love-resources.
Comment on lines
+296
to
+298
| app.post('/guestToken', async (req, res) => { | ||
| await guestManager.handleGuestToken(req, res) | ||
| }) |
Two runtime errors surfaced by CI's model bundle step (rush bundle/get-model), which tsc does not catch: - models/love: 'LoveNotificationGroup' was declared in both the base love plugin and the models mergeIds, tripping mergeIds' identify-overwrites guard. Keep it in the base plugin only. - models/time: the 'AccountRole' value import was dropped during a conflict resolution while still used (AccountRole.Guest/ReadOnlyGuest/User) — restore it. Verified locally: 'rushx get-model' for pod-server now builds the model.
The guest-identity commit carried a dev/tool restore-CLI convenience (auto-including channel/contact domains) unrelated to office/video. It's not needed for the feature and touching the dev/tool project makes CI's fast-format lint the whole (latently lint-drifted) project. Revert to develop.
Local 'rush build' transpiles (esbuild) without full typecheck; CI's 'rush validate' (tsc) surfaced real type errors from the port: services/love: - client.ts: getClient must return RestClient(token, workspace) via createRestClient — workspaceClient/others depend on RestClient ops. - config.ts: add missing UseEgressWebHook flag (used by recordings.ts). - main.ts: our PlatformQueue has no createBatchConsumer; use createConsumer. - polling.ts: pass the required participantMetadata arg to upsertParticipantFromLiveKit. - workspaceClient.ts: disable Drive file creation in saveFile (matches fork tip: shared Drive bypasses room ACL; RestClient isn't a TxOperations) and default participant x/y. pod-ai-bot (adapted to the new meeting-based love model; kept our non-whisper transcription path): - TranscriptionStatus -> TranscriptionState (InProgress->Transcribing, Idle->NotStarted). - ConnectMeetingRequest/DisconnectMeetingRequest now carry meetingId; resolve the room from the meeting; ParticipantInfo now needs kind:'agent' + meeting. Verified: rush validate passes for pod-love and pod-ai-bot.
The isMeeting mock checked event.meetingId, but the test cases pass { room }
(and the fork tip's mock checks .room) — so isMeeting returned false and the
meeting-scheduled notification assertions saw 0 calls. Align the mock with
.room to match the test cases and the fork tip.
Verified: pod-calendar-mailer tests pass (17/17).
LoginAppBase.svelte (brought in for the guest-login shim) @use'd ./themes/intabia.scss and ./themes/huly.scss, which come from the un-ported intabia login-theme rework and don't exist here. svelte-loader failed with 'Can't find stylesheet to import', which broke both svelte-check and the front webpack production build (@hcengineering/prod package) — and thus the uitest/docker-build jobs. The unbranded shim needs neither; remove them.
The ported ButtonBase.svelte (from 'Fixes for room office display') referenced $themeStore.accent, AccentColor.Intabia, and a Spinner color prop — all from the un-ported intabia theme rework. @hcengineering/theme has no AccentColor here, so it was a latent runtime crash, and since ButtonBase is imported everywhere, svelte-check type-checked it into every package and failed them all (tracker/time/view/ui/uploader/text-editor/love). Revert to develop.
FloorPreview.svelte (from 'Hide debug actions in office') gates debug offices actions on getMetadata(platform.metadata.DevModel), but our @hcengineering/ platform lacked that metadata key (fork-only). Declare it as Metadata<boolean>; unset means debug actions stay hidden, the intended default.
- LoginAppBase: drop 'intabia' theme comparisons and CSS class directives (unbranded shim keeps only the 'huly' login theme) - ConfirmationSend: cast setTimeout result to number to satisfy the number|undefined handle type - love-resources: add ambient image module declarations for the login-resources components reused by the guest meeting view Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BZnVtCWH1hTH7EisaBdT7T
- services/love/main.ts: remove unused WorkspaceUuid import (the eslint error that failed the CI formatting job) - Apply prettier fixes to ported files flagged by rush fast-format (services/love, models/love, pods/server, login-resources, love-resources) so the formatting diff check is clean Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BZnVtCWH1hTH7EisaBdT7T
Backend blockers found during review of the office/video port: - rpc.ts (#1 broken access control, #2 modifiedBy spoofing): the six direct /api/v1/{create,addCollection,update,createMixin,updateMixin, remove} endpoints build their client via wrapPipeline(...,true), which runs as the system account and bypasses space/role/read-only checks. Gate them to system/service accounts (the only legitimate caller, e.g. the love service which connects with a system token). Regular clients must use the permission-checked /api/v1/tx path. This also stops non-system callers from spoofing modifiedBy. - guests.ts (#3 guest-token secret): sign/verify the guest platform token with the platform SECRET instead of the LiveKit API secret, so it validates against the transactor without conflating the two secrets. - transient.ts (#4 TransientMiddleware): clear the ttlChecker interval in a new close() override (timer leak); detect removes via tx._class (was tx.objectClass, never TxRemoveDoc, so removes re-added the object with a fresh TTL); delete expired entries from ttlObjectMap in checkTTL (map grew unbounded and re-broadcast every second). - FloorPreview.svelte (#9 committed debug scaffolding): remove the dev-only Debug/Clear-AI-Bot/Search-Accounts menu actions and their functions, which hardcoded personal emails and logged PII. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BZnVtCWH1hTH7EisaBdT7T
Follow-up review fixes for the office/video port: - #5 guest-join room access (services/love guests.ts, workspaceClient.ts): enforce the room's live access server-side. A host who set the room to DND (locked) is no longer joinable via a previously shared guest link. Added WorkspaceClient.findRoomById and check the Room (not the meeting's creation-time snapshot). Knock rooms stay allowed — the shared link is the host's authorization. - #7 guest-info polling (GuestMeetingApp.svelte): fetch /guestInfo once per guest-token change instead of on every 1s tick, which POSTed the love service every second and re-ran workspace select/navigate each time. Also fixed the dead 'resolving' flag so the loading state and in-flight guard actually work. - #8 invite state machine (invites.ts, meetings.ts): * incoming invites now require status==='pending', so accepted/declined invites stop showing the button and knock sound during their TTL * knock-sound stop is guarded by incoming.length===0 (was inverted: stopped the sound while an invite was still pending) * connectToMeeting resets currentMeeting/currentMeetingRoom on any failure (connect error or unresolved person) so the guard no longer permanently blocks retry Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BZnVtCWH1hTH7EisaBdT7T
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR introduces guest meeting functionality, enhances the LiveKit integration with webhook and polling support, and refactors the meeting invite system. The changes enable external guests to join meetings without authentication while maintaining security through token-based access.
Key Changes
Guest Meeting Support
GuestJoinPopup.svelte,GuestMeetingApp.svelte,GuestParticipantView.svelte,GuestParticipantsListView.svelte,GuestControlBar.svelte) for unauthenticated guest participation/guestJoinendpointguests.tsservice for guest account and token managementLiveKit Backend Integration
webhook.ts) for handling LiveKit events (participant join/leave, recording completion)polling.ts) for periodic room state synchronizationrecordings.ts) with support for multiple formats and S3 storageworkspaceClient.tswith RestClient integration and meeting minutes managementMeeting Invite System Refactor
IncomingInvitePopup.svelteandOutgoingInvitePopup.sveltefor meeting invitationsInviteButton.svelteandInvitesExt.sveltefor invite UI controlsinvites.tsto use new subscription model for incoming invitesjoinRequests.tsand old invite response componentsUI/UX Improvements
speakingWhileMuted.ts,SpeakingWhileMutedIndicator.svelte)Core Infrastructure
queue.tsin love plugin)Login/Authentication
LoginAppBase.sveltefor base login application structureAuthLikeForm.sveltefor authentication form handlingLabel.svelteandtheme.tsfor login resourcesNotable Implementation Details
Breaking Changes
joinRequests.ts- replaced with unified invite systemhttps://claude.ai/code/session_01BZnVtCWH1hTH7EisaBdT7T