Compare commits

..

1 Commits

Author SHA1 Message Date
Elijah Duffy
b3a1419ed3 0.0.2 2026-02-02 18:44:46 -08:00
3 changed files with 17 additions and 600 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@svelte-toolkit/jitsi",
"version": "0.0.4",
"version": "0.0.2",
"repository": {
"type": "git",
"url": "https://gitea.auvem.com/svelte-toolkit/jitsi.git"

View File

@@ -1,19 +1,6 @@
<!-- @component
The Jitsi component is a lightweight wrapper that manages loading the Jitsi Meet External API
and joining a Jitsi meeting room. It accepts configuration options and provides a callback
when the API is ready for use.
WARNING: Assume that ALL properties are NOT reactive. Due to the nature of the Jitsi Meet
External API, changing properties after initialization will NOT update the Jitsi instance.
Instead, use the getAPI() method to interact with the Jitsi instance directly.
-->
<script lang="ts">
import { onMount, type Snippet } from 'svelte';
import type {
JitsiMeetExternalAPIOptions,
JitsiMeetExternalAPI
} from '$lib/jitsi-iframe-api.d.ts';
import { onMount } from 'svelte';
import { type JitsiMeetExternalAPIOptions, JitsiMeetExternalAPI } from './jitsi-iframe-api.js';
import type { ClassValue } from 'svelte/elements';
interface Props {
@@ -31,30 +18,13 @@ Instead, use the getAPI() method to interact with the Jitsi instance directly.
* Additional CSS classes to apply to the Jitsi container.
*/
class?: ClassValue;
/**
* Children are rendered inside the Jitsi container until the API is initialized.
*/
children?: Snippet;
/**
* Callback function that is called when the Jitsi API is loaded. Can
* be used to provide a loading indicator until the API is ready.
* @param api The Jitsi Meet External API instance.
*/
onready?: (api: JitsiMeetExternalAPI) => void;
}
let {
domain = 'https://meet.jit.si',
options,
class: classValue,
children,
onready
}: Props = $props();
let { domain = 'https://meet.jit.si', options, class: classValue }: Props = $props();
const src = $derived(`${new URL('external_api.js', domain).toString()}`);
let container: HTMLDivElement;
let ready = $state(false);
let api = $state<JitsiMeetExternalAPI | null>(null);
onMount(() => {
@@ -62,27 +32,13 @@ Instead, use the getAPI() method to interact with the Jitsi instance directly.
if (document.querySelectorAll('#jitsi-container').length > 1) {
console.warn('Duplicate Jitsi container detected. This may lead to unexpected behavior.');
}
});
const onload = () => {
if (typeof window.JitsiMeetExternalAPI === 'undefined') {
console.error('Jitsi Meet External API is not available on the window object.');
return;
}
ready = true;
// Initialize the Jitsi Meet External API
api = new window.JitsiMeetExternalAPI(new URL(domain).host, {
api = new JitsiMeetExternalAPI(new URL(domain).host, {
...options,
parentNode: container
});
if (api === null) {
console.error('Failed to initialize Jitsi Meet External API.');
return;
}
// Call the onready callback if provided
onready?.(api);
};
});
/**
* Get the Jitsi Meet External API instance.
@@ -94,11 +50,7 @@ Instead, use the getAPI() method to interact with the Jitsi instance directly.
</script>
<svelte:head>
<script {src} {onload}></script>
<script {src}></script>
</svelte:head>
<div id="jitsi-container" bind:this={container} class={[classValue]}>
{#if !ready}
{@render children?.()}
{/if}
</div>
<div id="jitsi-container" bind:this={container} class={[classValue]}></div>

View File

@@ -438,521 +438,28 @@ export interface JitsiMeetExternalAPIOptions {
}
interface ConfigOverwrite {
// Audio settings
startWithAudioMuted?: boolean;
startAudioMuted?: number;
startAudioOnly?: boolean;
startSilent?: boolean;
enableNoisyMicDetection?: boolean;
enableOpusRed?: boolean;
audioQuality?: {
stereo?: boolean;
opusMaxAverageBitrate?: number | null;
enableOpusDtx?: boolean;
};
noiseSuppression?: {
krisp?: {
enabled?: boolean;
logProcessStats?: boolean;
debugLogs?: boolean;
useBVC?: boolean;
bufferOverflowMS?: number;
};
};
disableAEC?: boolean;
disableAGC?: boolean;
disableAP?: boolean;
disableNS?: boolean;
// Video settings
startWithVideoMuted?: boolean;
startVideoMuted?: number;
maxFullResolutionParticipants?: number;
disableSimulcast?: boolean;
disableResponsiveTiles?: boolean;
constraints?: {
video?: {
height?: {
ideal?: number;
max?: number;
min?: number;
};
};
};
desktopSharingFrameRate?: {
min?: number;
max?: number;
};
screenShareSettings?: {
desktopPreferCurrentTab?: boolean;
desktopSystemAudio?: 'include' | 'exclude';
desktopSurfaceSwitching?: 'include' | 'exclude';
desktopDisplaySurface?: string;
desktopSelfBrowserSurface?: 'include' | 'exclude';
};
videoQuality?: {
codecPreferenceOrder?: ('AV1' | 'VP9' | 'VP8' | 'H264')[];
mobileCodecPreferenceOrder?: ('AV1' | 'VP9' | 'VP8' | 'H264')[];
screenshareCodec?: string;
mobileScreenshareCodec?: string;
enableAdaptiveMode?: boolean;
minHeightForQualityLvl?: Record<number, 'low' | 'standard' | 'high'>;
};
// Prejoin configuration (replaces prejoinPageEnabled)
prejoinConfig?: {
enabled?: boolean;
hideDisplayName?: boolean;
hideExtraJoinButtons?: ('no-audio' | 'by-phone')[];
preCallTestEnabled?: boolean;
preCallTestICEUrl?: string;
showHangUp?: boolean;
};
/** @deprecated Use prejoinConfig.enabled instead */
prejoinPageEnabled?: boolean;
// Lobby configuration
lobby?: {
autoKnock?: boolean;
enableChat?: boolean;
showHangUp?: boolean;
};
/** @deprecated Use lobby.autoKnock instead */
autoKnockLobby?: boolean;
/** @deprecated Use lobby.enableChat instead */
enableLobbyChat?: boolean;
// Security UI configuration
securityUi?: {
hideLobbyButton?: boolean;
disableLobbyPassword?: boolean;
};
/** @deprecated Use securityUi.hideLobbyButton instead */
hideLobbyButton?: boolean;
// Deep linking configuration
deeplinking?: {
disabled?: boolean;
hideLogo?: boolean;
desktop?: {
appName?: string;
appScheme?: string;
download?: {
linux?: string;
macos?: string;
windows?: string;
};
enabled?: boolean;
};
ios?: {
appName?: string;
appScheme?: string;
downloadLink?: string;
};
android?: {
appName?: string;
appScheme?: string;
downloadLink?: string;
appPackage?: string;
fDroidUrl?: string;
};
};
/** @deprecated Use deeplinking.disabled instead */
disableDeepLinking?: boolean;
// Welcome page configuration
welcomePage?: {
disabled?: boolean;
customUrl?: string;
};
// Recording configuration
recordings?: {
recordAudioAndVideo?: boolean;
suggestRecording?: boolean;
showPrejoinWarning?: boolean;
showRecordingLink?: boolean;
requireConsent?: boolean;
skipConsentInMeeting?: boolean;
consentLearnMoreLink?: string;
};
recordingService?: {
enabled?: boolean;
sharingEnabled?: boolean;
hideStorageWarning?: boolean;
};
localRecording?: {
disable?: boolean;
notifyAllParticipants?: boolean;
disableSelfRecording?: boolean;
};
// Live streaming configuration
liveStreaming?: {
enabled?: boolean;
termsLink?: string;
dataPrivacyLink?: string;
validatorRegExpString?: string;
helpLink?: string;
};
// Transcription configuration
transcription?: {
enabled?: boolean;
useAppLanguage?: boolean;
preferredLanguage?: string;
customLanguages?: Record<string, string>;
autoTranscribeOnRecord?: boolean;
autoCaptionOnTranscribe?: boolean;
disableClosedCaptions?: boolean;
};
// Toolbar configuration
toolbarButtons?: ToolbarButton[];
mainToolbarButtons?: ToolbarButton[][];
reducedUImainToolbarButtons?: ToolbarButton[];
reducedUIEnabled?: boolean;
buttonsWithNotifyClick?: (ToolbarButton | ButtonWithNotifyClick)[];
participantMenuButtonsWithNotifyClick?: (string | ButtonWithNotifyClick)[];
hiddenPremeetingButtons?: (
| 'microphone'
| 'camera'
| 'select-background'
| 'invite'
| 'settings'
)[];
customToolbarButtons?: Array<{
icon: string;
id: string;
text: string;
backgroundColor?: string;
}>;
customParticipantMenuButtons?: Array<{ icon: string; id: string; text: string }>;
toolbar?: {
initialTimeout?: number;
timeout?: number;
alwaysVisible?: boolean;
autoHideWhileChatIsOpen?: boolean;
};
// UI settings
prejoinPageEnabled?: boolean;
enableNoisyMicDetection?: boolean;
enableClosePage?: boolean;
disableInviteFunctions?: boolean;
disableModeratorIndicator?: boolean;
enableLobbyChat?: boolean;
hideLobbyButton?: boolean;
enableInsecureRoomNameWarning?: boolean;
disableReactions?: boolean;
disableReactionsModeration?: boolean;
disableReactionsInChat?: boolean;
disablePolls?: boolean;
disableChat?: boolean;
disableSelfDemote?: boolean;
disableSelfView?: boolean;
disableSelfViewSettings?: boolean;
showChatPermissionsModeratorSetting?: boolean;
disableShortcuts?: boolean;
disableInitialGUM?: boolean;
disable1On1Mode?: boolean | null;
defaultLocalDisplayName?: string;
defaultRemoteDisplayName?: string;
hideDisplayName?: boolean;
hideDominantSpeakerBadge?: boolean;
defaultLanguage?: string;
disableProfile?: boolean;
hideEmailInSettings?: boolean;
requireDisplayName?: boolean;
readOnlyName?: boolean;
enableWebHIDFeature?: boolean;
doNotStoreRoom?: boolean;
disableLocalVideoFlip?: boolean;
doNotFlipLocalVideo?: boolean;
disableVirtualBackground?: boolean;
disableAddingBackgroundImages?: boolean;
backgroundAlpha?: number;
disableTileView?: boolean;
disableTileEnlargement?: boolean;
hideConferenceSubject?: boolean;
hideConferenceTimer?: boolean;
hideRecordingLabel?: boolean;
hideParticipantsStats?: boolean;
subject?: string;
localSubject?: string;
disableChatSmileys?: boolean;
disableFilmstripAutohiding?: boolean;
disableCameraTintForeground?: boolean;
// Filmstrip configuration
filmstrip?: {
disabled?: boolean;
disableResizable?: boolean;
disableStageFilmstrip?: boolean;
stageFilmstripParticipants?: number;
disableTopPanel?: boolean;
minParticipantCountForTopPanel?: number;
initialWidth?: number;
alwaysShowResizeBar?: boolean;
};
// Tile view configuration
tileView?: {
disabled?: boolean;
numberOfVisibleTiles?: number;
};
// Participants pane configuration
participantsPane?: {
enabled?: boolean;
hideModeratorSettingsTab?: boolean;
hideMoreActionsButton?: boolean;
hideMuteAllButton?: boolean;
};
// Breakout rooms configuration
breakoutRooms?: {
hideAddRoomButton?: boolean;
hideAutoAssignButton?: boolean;
hideJoinRoomButton?: boolean;
};
// Raised hands configuration
raisedHands?: {
disableLowerHandByModerator?: boolean;
disableLowerHandNotification?: boolean;
disableNextSpeakerNotification?: boolean;
disableRemoveRaisedHandOnFocus?: boolean;
};
disableRemoveRaisedHandOnFocus?: boolean;
// Speaker stats configuration
speakerStats?: {
disabled?: boolean;
disableSearch?: boolean;
order?: ('role' | 'name' | 'hasLeft')[];
};
// Connection indicators configuration
connectionIndicators?: {
autoHide?: boolean;
autoHideTimeout?: number;
disabled?: boolean;
disableDetails?: boolean;
inactiveDisabled?: boolean;
};
// Remote video menu configuration
remoteVideoMenu?: {
disabled?: boolean;
disableDemote?: boolean;
disableKick?: boolean;
disableGrantModerator?: boolean;
disablePrivateChat?: 'all' | 'allow-moderator-chat' | 'disable-visitor-chat';
};
disableRemoteMute?: boolean;
// Face landmarks configuration
faceLandmarks?: {
enableFaceCentering?: boolean;
enableFaceExpressionsDetection?: boolean;
enableDisplayFaceExpressions?: boolean;
enableRTCStats?: boolean;
faceCenteringThreshold?: number;
captureInterval?: number;
};
// Notification settings
notificationTimeouts?: {
short?: number;
medium?: number;
long?: number;
extraLong?: number;
sticky?: number;
};
notifications?: string[];
disabledNotifications?: string[];
// Conference info configuration
conferenceInfo?: {
alwaysVisible?: string[];
autoHide?: string[];
};
// Giphy configuration
giphy?: {
enabled?: boolean;
sdkKey?: string;
displayMode?: 'tile' | 'chat' | 'all';
tileTime?: number;
rating?: 'g' | 'pg' | 'pg-13' | 'r';
};
// Whiteboard configuration
whiteboard?: {
enabled?: boolean;
collabServerBaseUrl?: string;
userLimit?: number;
limitUrl?: string;
};
// E2EE configuration
e2ee?: {
labels?: {
description?: string;
label?: string;
tooltip?: string;
warning?: string;
};
externallyManagedKey?: boolean;
};
// Visitors configuration
visitors?: {
enableMediaOnPromote?: {
audio?: boolean;
video?: boolean;
};
hideVisitorCountForVisitors?: boolean;
showJoinMeetingDialog?: boolean;
};
// P2P configuration
p2p?: {
enabled?: boolean;
iceTransportPolicy?: 'all' | 'relay';
codecPreferenceOrder?: ('AV1' | 'VP9' | 'VP8' | 'H264')[];
mobileCodecPreferenceOrder?: ('AV1' | 'VP9' | 'VP8' | 'H264')[];
screenshareCodec?: string;
mobileScreenshareCodec?: string;
backToP2PDelay?: number;
stunServers?: Array<{ urls: string }>;
};
// Testing/experimental features
testing?: {
assumeBandwidth?: boolean;
enableAV1ForFF?: boolean;
enableCodecSelectionAPI?: boolean;
p2pTestMode?: boolean;
testMode?: boolean;
noAutoPlayVideo?: boolean;
skipInterimTranscriptions?: boolean;
dumpTranscript?: boolean;
debugAudioLevels?: boolean;
failICE?: boolean;
showSpotConsentDialog?: boolean;
};
// Analytics configuration
analytics?: {
disabled?: boolean;
rtcstatsEnabled?: boolean;
rtcstatsStoreLogs?: boolean;
rtcstatsEndpoint?: string;
rtcstatsPollInterval?: number;
rtcstatsSendSdp?: boolean;
watchRTCEnabled?: boolean;
};
// Gravatar configuration
gravatar?: {
baseUrl?: string;
disabled?: boolean;
};
// Legal URLs
legalUrls?: {
helpCentre?: string;
privacy?: string;
terms?: string;
};
// Other settings
apiLogLevels?: LogLevel[];
toolbarButtons?: ToolbarButton[];
buttonsWithNotifyClick?: (ToolbarButton | ButtonWithNotifyClick)[];
mouseMoveCallbackInterval?: number;
channelLastN?: number;
startLastN?: number;
useHostPageLocalStorage?: boolean;
disableRtx?: boolean;
enableTcc?: boolean;
enableRemb?: boolean;
enableForcedReload?: boolean;
useTurnUdp?: boolean;
enableEncodedTransformSupport?: boolean;
disableThirdPartyRequests?: boolean;
enableCalendarIntegration?: boolean;
notifyOnConferenceDestruction?: boolean;
feedbackPercentage?: number;
roomPasswordNumberOfDigits?: number | false;
noticeMessage?: string;
enableTalkWhileMuted?: boolean;
forceTurnRelay?: boolean;
hideLoginButton?: boolean;
disableWebrtcStats?: boolean;
disableShowMoreStats?: boolean;
etherpad_base?: string;
openSharedDocumentOnJoin?: boolean;
screenshotCapture?: {
enabled?: boolean;
mode?: 'recording' | 'always';
faceLandmarks?: {
faceCenteringThreshold?: number;
};
webrtcIceUdpDisable?: boolean;
webrtcIceTcpDisable?: boolean;
disableBeforeUnloadHandlers?: boolean;
// Logging configuration
logging?: {
defaultLogLevel?: 'trace' | 'debug' | 'info' | 'log' | 'warn' | 'error';
disableLogCollector?: boolean;
loggers?: Record<string, string>;
};
// File sharing configuration
fileSharing?: {
apiUrl?: string;
enabled?: boolean;
maxFileSize?: number;
};
// Dropbox integration
dropbox?: {
appKey?: string;
redirectURI?: string;
};
// Dynamic branding
dynamicBrandingUrl?: string;
// Shared video allowed domains
sharedVideoAllowedURLDomains?: string[];
// CORS avatar URLs
corsAvatarURLs?: string[];
// Recording limit
recordingLimit?: {
limit?: number;
appName?: string;
appURL?: string;
};
// Chrome extension banner
chromeExtensionBanner?: {
url?: string;
edgeUrl?: string;
chromeExtensionsInfo?: Array<{
id: string;
path: string;
}>;
};
// Allow any additional config options
apiLogLevels?: LogLevel[];
[key: string]: unknown;
}
/**
* @deprecated Most interfaceConfig options are being migrated to config.js.
* Use configOverwrite instead where possible.
*/
interface InterfaceConfigOverwrite {
/** @deprecated Use config.disableModeratorIndicator instead */
DISABLE_DOMINANT_SPEAKER_INDICATOR?: boolean;
TILE_VIEW_MAX_COLUMNS?: number;
SHOW_JITSI_WATERMARK?: boolean;
@@ -960,7 +467,6 @@ interface InterfaceConfigOverwrite {
SHOW_BRAND_WATERMARK?: boolean;
SHOW_POWERED_BY?: boolean;
SHOW_PROMOTIONAL_CLOSE_PAGE?: boolean;
/** @deprecated Use config.toolbarButtons instead */
TOOLBAR_BUTTONS?: ToolbarButton[];
SETTINGS_SECTIONS?: SettingsSection[];
VIDEO_LAYOUT_FIT?: 'both' | 'width' | 'height';
@@ -968,44 +474,8 @@ interface InterfaceConfigOverwrite {
FILM_STRIP_MAX_HEIGHT?: number;
MOBILE_APP_PROMO?: boolean;
HIDE_INVITE_MORE_HEADER?: boolean;
/** @deprecated Use config.disabledSounds instead */
DISABLE_JOIN_LEAVE_NOTIFICATIONS?: boolean;
DISABLE_VIDEO_BACKGROUND?: boolean;
DEFAULT_BACKGROUND?: string;
DEFAULT_WELCOME_PAGE_LOGO_URL?: string;
DEFAULT_LOGO_URL?: string;
JITSI_WATERMARK_LINK?: string;
BRAND_WATERMARK_LINK?: string;
APP_NAME?: string;
NATIVE_APP_NAME?: string;
PROVIDER_NAME?: string;
LANG_DETECTION?: boolean;
ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT?: number;
MAXIMUM_ZOOMING_COEFFICIENT?: number;
SUPPORT_URL?: string;
CONNECTION_INDICATOR_AUTO_HIDE_ENABLED?: boolean;
CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT?: number;
CONNECTION_INDICATOR_DISABLED?: boolean;
AUTO_PIN_LATEST_SCREEN_SHARE?: string;
DISABLE_FOCUS_INDICATOR?: boolean;
DISABLE_PRESENCE_STATUS?: boolean;
DISABLE_TRANSCRIPTION_SUBTITLES?: boolean;
DISABLE_RINGING?: boolean;
AUDIO_LEVEL_PRIMARY_COLOR?: string;
AUDIO_LEVEL_SECONDARY_COLOR?: string;
FILMSTRIP_MAX_HEIGHT?: number;
GENERATE_ROOMNAMES_ON_WELCOME_PAGE?: boolean;
HIDE_DEEP_LINKING_LOGO?: boolean;
INITIAL_TOOLBAR_TIMEOUT?: number;
TOOLBAR_TIMEOUT?: number;
TOOLBAR_ALWAYS_VISIBLE?: boolean;
LOCAL_THUMBNAIL_RATIO?: number;
REMOTE_THUMBNAIL_RATIO?: number;
LIVE_STREAMING_HELP_LINK?: string;
POLICY_LOGO?: string;
RECENT_LIST_ENABLED?: boolean;
SHOW_CHROME_EXTENSION_BANNER?: boolean;
VIDEO_QUALITY_LABEL_DISABLED?: boolean;
[key: string]: unknown;
}
@@ -1808,26 +1278,21 @@ type ToolbarButton =
| 'dock-iframe'
| 'download'
| 'embedmeeting'
| 'end-meeting'
| 'etherpad'
| 'feedback'
| 'filmstrip'
| 'fullscreen'
| 'hangup'
| 'hangup-menu'
| 'help'
| 'highlight'
| 'invite'
| 'linktosalesforce'
| 'livestreaming'
| 'microphone'
| 'mute-everyone'
| 'mute-video-everyone'
| 'noisesuppression'
| 'participants-pane'
| 'profile'
| 'raisehand'
| 'reactions'
| 'recording'
| 'security'
| 'select-background'