fix(idaa): ensure breakout links preserve site access key and uuid
Proactively re-injects 'key' (site access key) and 'uuid' (Novi token) into 'Open Externally' and 'Copy Link' URLs on the Video Conferences page. This prevents authentication failures when members open meetings in a new browser tab after SvelteKit internal navigation has dropped the bootstrap parameters. Updated CLIENT__IDAA_and_customized_mods.md to document the requirement for these keys in breakout URLs.
This commit is contained in:
@@ -31,6 +31,17 @@ IDAA is a private membership organization for physicians in recovery. They use t
|
||||
|
||||
IDAA's Aether instance is embedded as an **iframe inside their existing Novi-powered website** (`idaa.org`). Novi is their external Association Management System (AMS) — it handles membership records and authentication. Aether receives the member context via URL parameters on iframe load.
|
||||
|
||||
### Breakout Links and Iframe Persistence
|
||||
|
||||
Members often need to open Jitsi meetings outside the Novi iframe (e.g., for full-screen features or on mobile). These are referred to as **Breakout Links**.
|
||||
|
||||
- **The Problem:** SvelteKit client-side navigation within the iframe often drops "bootstrap" query parameters like `?key=...` (site access key) and `?uuid=...` (Novi identity token).
|
||||
- **The Requirement:** When a member breaks out of the iframe into a new browser tab, these keys **must** be present in the URL. Without them, the member will hit the site-domain gate or the IDAA auth gate and see "Access Denied."
|
||||
- **The Solution:** The Video Conferences page uses a derived `breakout_url` that proactively re-injects the missing `key` (from `$ae_loc.allow_access`) and `uuid` (from `$idaa_loc.novi_uuid`) before generating the external link.
|
||||
|
||||
**Example Breakout URL:**
|
||||
`https://client.oneskyit.com/idaa/video_conferences?uuid=...&key=...&room=...`
|
||||
|
||||
---
|
||||
|
||||
## Architecture: Composite Module
|
||||
|
||||
@@ -57,17 +57,57 @@ let duration_timer_id: any = $state(null);
|
||||
let show_breakout_modal: boolean = $state(false);
|
||||
let breakout_link_copied: boolean = $state(false);
|
||||
|
||||
const breakout_url = $derived.by(() => {
|
||||
const url = new URL($page.url.href);
|
||||
|
||||
// Proactively inject site access key if missing or empty.
|
||||
// WHY: SvelteKit internal navigation drops bootstrap params (key, uuid). When a member
|
||||
// "breaks out" of the Novi iframe, they need these keys in the URL to satisfy the
|
||||
// site-domain gate and the IDAA Novi auth gate in a fresh tab.
|
||||
if (!url.searchParams.get('key')) {
|
||||
const access_key = $ae_loc.allow_access;
|
||||
if (typeof access_key === 'string' && access_key) {
|
||||
url.searchParams.set('key', access_key);
|
||||
} else if ($ae_loc.site_access_key) {
|
||||
url.searchParams.set('key', $ae_loc.site_access_key);
|
||||
}
|
||||
}
|
||||
|
||||
// Proactively inject Novi UUID if missing or empty (ensures auth persistence).
|
||||
if (!url.searchParams.get('uuid') && $idaa_loc.novi_uuid) {
|
||||
url.searchParams.set('uuid', $idaa_loc.novi_uuid);
|
||||
}
|
||||
|
||||
return url.href;
|
||||
});
|
||||
|
||||
function copy_meeting_link() {
|
||||
navigator.clipboard.writeText($page.url.href).then(() => {
|
||||
navigator.clipboard.writeText(breakout_url).then(() => {
|
||||
breakout_link_copied = true;
|
||||
setTimeout(() => (breakout_link_copied = false), 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function build_jitsi_reports_href() {
|
||||
const url = new URL($page.url);
|
||||
const url = new URL($page.url.href);
|
||||
url.pathname = '/idaa/jitsi_reports';
|
||||
url.searchParams.delete('room');
|
||||
|
||||
// Proactively inject site access key if missing or empty
|
||||
if (!url.searchParams.get('key')) {
|
||||
const access_key = $ae_loc.allow_access;
|
||||
if (typeof access_key === 'string' && access_key) {
|
||||
url.searchParams.set('key', access_key);
|
||||
} else if ($ae_loc.site_access_key) {
|
||||
url.searchParams.set('key', $ae_loc.site_access_key);
|
||||
}
|
||||
}
|
||||
|
||||
// Proactively inject Novi UUID if missing or empty
|
||||
if (!url.searchParams.get('uuid') && $idaa_loc.novi_uuid) {
|
||||
url.searchParams.set('uuid', $idaa_loc.novi_uuid);
|
||||
}
|
||||
|
||||
return `${url.pathname}${url.search}${url.hash}`;
|
||||
}
|
||||
|
||||
@@ -1172,7 +1212,7 @@ async function init_jitsi() {
|
||||
mt-2 flex w-full flex-col flex-wrap items-center justify-center gap-1
|
||||
border-t-2 border-dashed border-gray-400 pt-2 sm:flex-row">
|
||||
<MyClipboard
|
||||
value={encodeURI($page.url.href)}
|
||||
value={encodeURI(breakout_url)}
|
||||
btn_text="Copy Break-out Link"
|
||||
btn_title="Copy a link to this meeting that can be opened outside of the Novi iframe."
|
||||
btn_class="mt-2 px-2 py-1 bg-indigo-400 text-white rounded hover:bg-indigo-500"
|
||||
@@ -1312,7 +1352,7 @@ async function init_jitsi() {
|
||||
{breakout_link_copied ? 'Copied!' : 'Copy Link'}
|
||||
</button>
|
||||
<a
|
||||
href={$page.url.href}
|
||||
href={breakout_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onclick={() => (show_breakout_modal = false)}
|
||||
@@ -1327,7 +1367,7 @@ async function init_jitsi() {
|
||||
<textarea
|
||||
readonly
|
||||
rows="3"
|
||||
value={$page.url.href}
|
||||
value={breakout_url}
|
||||
onclick={(e) => (e.target as HTMLTextAreaElement).select()}
|
||||
class="w-full cursor-text resize-none rounded border border-gray-200 bg-gray-50 px-2 py-1.5 font-mono text-xs text-gray-700 focus:outline-none"
|
||||
title="Click to select all, then copy (ctrl/cmd + C)"
|
||||
|
||||
Reference in New Issue
Block a user