Files
zep/src/SpacetimeProvider.svelte
T

183 lines
4.7 KiB
Svelte

<script lang="ts">
import { untrack } from "svelte";
import { auth } from "./auth/auth.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
if (auth.isLoading) return;
const currentToken = auth.user?.id_token;
// Only (re)create the builder if we don't have one, or if the token changed.
if (!builder || currentToken !== lastUsedOidcToken) {
console.log(`[SpacetimeProvider] Initializing connection (Auth Settled). OIDC present: ${!!currentToken}`);
untrack(() => {
builder = connectionBuilder(currentToken);
lastUsedOidcToken = currentToken;
providerKey += 1; // Force re-mount of InnerSpacetimeDBProvider for a clean handshake
});
}
});
// Reactive labels for the loading screen
const host = getStdbHost();
const dbName = getStdbDbName();
// Unified status message logic
const statusInfo = $derived.by(() => {
if (auth.isLoading) {
return {
title: "Authenticating...",
icon: "fa-id-card",
message: "Verifying your identity with the provider."
};
}
if (!builder) {
return {
title: "Preparing Handshake...",
icon: "fa-key",
message: "Finalizing security credentials."
};
}
// Default connecting state
return {
title: "Connecting to SpacetimeDB...",
icon: "fa-circle-notch",
spin: true,
message: "Establishing a secure connection to the chat server."
};
});
</script>
{#if builder && !auth.isLoading}
{#key providerKey}
<InnerSpacetimeDBProvider
{builder}
{onCancel}
{host}
{dbName}
oidcToken={auth.user?.id_token}
>
{@render children()}
</InnerSpacetimeDBProvider>
{/key}
{:else}
<div class="login-screen">
<div class="login-card" style="text-align: center;">
<i class="fas {statusInfo.icon} {statusInfo.spin ? 'fa-spin' : 'fa-pulse'}" style="font-size: 3rem; color: var(--brand); margin-bottom: 20px;"></i>
<h1>{statusInfo.title}</h1>
<p style="color: var(--text-muted); margin-top: 8px; margin-bottom: 24px;">{statusInfo.message}</p>
<div class="connection-details-box">
<div class="connection-detail">
<div class="detail-label">Host</div>
<div class="detail-value">{host}</div>
</div>
<div class="connection-detail">
<div class="detail-label">Database</div>
<div class="detail-value">{dbName}</div>
</div>
</div>
{#if onCancel}
<button
onclick={onCancel}
class="btn-secondary"
style="width: 100%;"
>
Cancel
</button>
{/if}
</div>
</div>
{/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;
}
.connection-details-box {
background-color: var(--background-tertiary);
padding: 16px;
border-radius: 8px;
margin-bottom: 24px;
text-align: left;
font-size: 0.8rem;
border: 1px solid var(--background-modifier-accent);
display: flex;
flex-direction: column;
gap: 12px;
width: 100%;
box-sizing: border-box;
}
.detail-label {
color: var(--text-muted);
font-weight: 800;
text-transform: uppercase;
font-size: 0.65rem;
margin-bottom: 4px;
letter-spacing: 0.05em;
}
.detail-value {
color: var(--text-normal);
font-family: var(--font-code);
word-break: break-all;
line-height: 1.4;
}
</style>