Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/plugins/react-custom-html-parser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function KatexRenderer({

useEffect(() => {
let mounted = true;
void Promise.all([import('katex'), import('katex/dist/katex.min.css')]).then(([katex]) => {
void import('katex').then((katex) => {
if (mounted) {
setHtml(katex.default.renderToString(math, { throwOnError: false, displayMode }));
}
Expand Down
30 changes: 30 additions & 0 deletions src/app/utils/mediaTransport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,36 @@ describe('fetchMediaBlob', () => {
TEST_TIMEOUT
);

it('selects the JSON-encoded active session instead of falling back to the first account', async () => {
const { getActiveMediaSession, getCurrentMediaSessionScope } = await import('./mediaTransport');

localStorage.setItem(
'matrixSessions',
JSON.stringify([
{
baseUrl: 'https://matrix.example.org',
userId: '@alice:example.org',
deviceId: 'ALICE',
accessToken: 'alice-token',
},
{
baseUrl: 'https://other.example.org',
userId: '@bob:example.org',
deviceId: 'BOB',
accessToken: 'bob-token',
},
])
);
localStorage.setItem('matrixActiveSession', JSON.stringify('@bob:example.org'));

expect(getActiveMediaSession()).toEqual({
baseUrl: 'https://other.example.org',
accessToken: 'bob-token',
userId: '@bob:example.org',
});
expect(getCurrentMediaSessionScope()).toBe('@bob:example.org');
});

it(
'uses caller-provided auth and cache scope when present',
async () => {
Expand Down
15 changes: 14 additions & 1 deletion src/app/utils/mediaTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,24 @@ function parseStoredSessions(): StoredSession[] {
}
}

function getStoredActiveSessionId(): string | undefined {
const raw = localStorage.getItem(ACTIVE_SESSION_KEY);
if (!raw) return undefined;

try {
const parsed = JSON.parse(raw);
return typeof parsed === 'string' ? parsed : undefined;
} catch {
// Keep reading pre-multi-account values written without JSON encoding.
return raw;
}
}

function getActiveStoredSession(): StoredSession | undefined {
if (typeof localStorage === 'undefined') return undefined;

const sessions = parseStoredSessions();
const activeSessionId = localStorage.getItem(ACTIVE_SESSION_KEY);
const activeSessionId = getStoredActiveSessionId();
return (
(activeSessionId
? sessions.find((session) => session.userId === activeSessionId)
Expand Down
26 changes: 26 additions & 0 deletions src/app/utils/tauriMediaAuth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,30 @@ describe('Tauri media session coordinator', () => {
const scopes = commands.setMediaSession.mock.calls.map(([params]) => params.scope);
expect(scopes).toEqual(['@a:matrix.example', '@a:matrix.example']);
});

it('syncs the native session when the active account changes in this window', async () => {
mediaTransport.getActiveMediaSession
.mockReturnValueOnce({
baseUrl: 'https://one.example',
accessToken: 'one',
userId: '@a:one.example',
})
.mockReturnValue({
baseUrl: 'https://two.example',
accessToken: 'two',
userId: '@b:two.example',
});

await initTauriMediaSession();
commands.setMediaSession.mockClear();

window.dispatchEvent(new Event('sable-session-changed'));
await vi.waitFor(() => expect(commands.setMediaSession).toHaveBeenCalledTimes(1));

expect(commands.setMediaSession).toHaveBeenCalledWith({
baseUrl: 'https://two.example',
token: 'two',
scope: '@b:two.example',
});
});
});
16 changes: 11 additions & 5 deletions src/app/utils/tauriMediaAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getActiveMediaSession } from './mediaTransport';
const log = createLogger('tauri-media-auth');

let pendingNativeWrite: Promise<void> = Promise.resolve();
let tauriMediaSessionListenersInstalled = false;

export const updateTauriMediaSession = (
baseUrl?: string,
Expand Down Expand Up @@ -41,9 +42,14 @@ const syncTauriMediaSession = (): Promise<void> => {
export const initTauriMediaSession = (): Promise<void> => {
if (!isTauri()) return Promise.resolve();

const initialSync = syncTauriMediaSession();
window.addEventListener('storage', () => {
void syncTauriMediaSession();
});
return initialSync;
if (!tauriMediaSessionListenersInstalled) {
const sync = () => {
void syncTauriMediaSession();
};
window.addEventListener('storage', sync);
window.addEventListener('sable-session-changed', sync);
tauriMediaSessionListenersInstalled = true;
}

return syncTauriMediaSession();
};
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '@fontsource/space-mono/400.css';
import '@fontsource/space-mono/700.css';
import '@fontsource/space-mono/400-italic.css';
import '@fontsource/space-mono/700-italic.css';
import 'katex/dist/katex.min.css';
import 'folds/dist/style.css';
import { configClass, varsClass } from 'folds';
import App from './app/pages/App';
Expand Down
2 changes: 1 addition & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export default defineConfig(({ command }) => {
clearScreen: false,
appType: 'spa',
publicDir: false,
base: buildConfig.base,
base: command === 'build' && isTauriBuild ? './' : buildConfig.base,
envPrefix: ['VITE_', 'TAURI_ENV_*'],
define: {
APP_VERSION: JSON.stringify(appVersion),
Expand Down
Loading