139 lines
4.0 KiB
Svelte
139 lines
4.0 KiB
Svelte
<script lang="ts">
|
|
import { untrack } from "svelte";
|
|
import { auth } from "./auth/auth.svelte";
|
|
import { connectionState } from "./connection.svelte";
|
|
import { connectionBuilder, getStdbHost, getStdbDbName } from "./config";
|
|
import InnerSpacetimeDBProvider from "./InnerSpacetimeDBProvider.svelte";
|
|
|
|
let { children, onCancel } = $props<{
|
|
children: any,
|
|
onCancel?: () => void
|
|
}>();
|
|
|
|
// 1. Connection Builder Lifecycle
|
|
// We MUST wait for OIDC to finish its loading/silent-renew phase
|
|
// before we construct the initial SpacetimeDB connection.
|
|
let builder = $state<any>(null);
|
|
let lastUsedOidcToken = $state<string | undefined>(undefined);
|
|
let providerKey = $state(0);
|
|
|
|
$effect(() => {
|
|
// Hold off until OIDC is settled for the first time
|
|
if (auth.isLoading) return;
|
|
|
|
const currentToken = auth.user?.id_token;
|
|
|
|
// 1. Initial creation
|
|
if (!builder) {
|
|
console.log(`[SpacetimeProvider] Initializing connection builder. OIDC present: ${!!currentToken}`);
|
|
untrack(() => {
|
|
builder = connectionBuilder(currentToken);
|
|
lastUsedOidcToken = currentToken;
|
|
providerKey += 1;
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 2. Identity transition (Logged out -> Logged in)
|
|
// If we were a guest (or null) and now have a token, we SHOULD remount
|
|
// to ensure the OIDC credentials take over completely.
|
|
if (currentToken && !lastUsedOidcToken) {
|
|
console.log("[SpacetimeProvider] Transitioning from Guest/None to OIDC session. Remounting...");
|
|
untrack(() => {
|
|
builder = connectionBuilder(currentToken);
|
|
lastUsedOidcToken = currentToken;
|
|
providerKey += 1;
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 3. Background Refresh (Token -> New Token)
|
|
// If it's just a refresh, we DON'T remount. We let InnerSpacetimeDBProvider
|
|
// handle the in-place upgrade via withToken.
|
|
if (currentToken && currentToken !== lastUsedOidcToken) {
|
|
console.log("[SpacetimeProvider] Background token refresh detected. Upgrading in-place.");
|
|
untrack(() => {
|
|
lastUsedOidcToken = currentToken;
|
|
// Notice we DON'T increment providerKey here
|
|
});
|
|
}
|
|
|
|
// 4. Logout (Token -> Null)
|
|
if (!currentToken && lastUsedOidcToken) {
|
|
console.log("[SpacetimeProvider] User logged out. Remounting for Guest mode.");
|
|
untrack(() => {
|
|
builder = connectionBuilder(undefined);
|
|
lastUsedOidcToken = undefined;
|
|
providerKey += 1;
|
|
});
|
|
}
|
|
});
|
|
|
|
// Reactive labels for the loading screen
|
|
const host = getStdbHost();
|
|
const dbName = getStdbDbName();
|
|
</script>
|
|
|
|
{#if !builder || (auth.isLoading && !auth.user)}
|
|
<div class="login-screen">
|
|
<div class="login-card" style="text-align: center;">
|
|
<i class="fas fa-id-card fa-spin" style="font-size: 3rem; color: var(--brand); margin-bottom: 20px;"></i>
|
|
<h1>Authenticating...</h1>
|
|
<p style="color: var(--text-muted); margin-top: 8px; margin-bottom: 24px;">Synchronizing your session credentials.</p>
|
|
</div>
|
|
</div>
|
|
{:else}
|
|
{#key providerKey}
|
|
<InnerSpacetimeDBProvider
|
|
{builder}
|
|
{onCancel}
|
|
{host}
|
|
{dbName}
|
|
oidcToken={auth.user?.id_token}
|
|
>
|
|
{@render children()}
|
|
</InnerSpacetimeDBProvider>
|
|
{/key}
|
|
{/if}
|
|
|
|
<style>
|
|
.login-screen {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100vh;
|
|
width: 100vw;
|
|
background: radial-gradient(
|
|
circle at center,
|
|
var(--background-secondary) 0%,
|
|
var(--background-tertiary) 100%
|
|
);
|
|
background-color: var(--background-tertiary);
|
|
}
|
|
|
|
.login-card {
|
|
background-color: var(--background-primary);
|
|
padding: 32px;
|
|
border-radius: 8px;
|
|
width: 480px;
|
|
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
text-align: center;
|
|
}
|
|
|
|
.login-card h1 {
|
|
color: var(--header-primary);
|
|
margin-bottom: 8px;
|
|
font-size: 24px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.login-card p {
|
|
color: var(--text-normal);
|
|
margin-bottom: 24px;
|
|
font-size: 16px;
|
|
}
|
|
</style>
|