|
20 | 20 | RecordModel,
|
21 | 21 | } from "pocketbase";
|
22 | 22 | import { customFetch } from "src/customFetch";
|
| 23 | + import { curryLog } from "src/debug"; |
23 | 24 | import { FeatureFlagManager, flags } from "src/flagManager";
|
24 | 25 |
|
25 | 26 | export let plugin: Live;
|
26 | 27 |
|
| 28 | + let errorLog = curryLog("LoggedIn.svelte", "error"); |
| 29 | +
|
27 | 30 | let lm: LoginManager;
|
28 | 31 | let automaticFlow = writable<boolean>(!Platform.isIosApp);
|
29 | 32 | let pending = writable<boolean>(false);
|
|
37 | 40 | let providers: Record<string, Provider> = {};
|
38 | 41 | let hasProviderInfo = writable<boolean>(false);
|
39 | 42 | const loginSettings = lm.loginSettings;
|
40 |
| - |
| 43 | +
|
41 | 44 | // Load cached providers from localStorage, keyed by auth URL
|
42 | 45 | let cachedProviders = writable<string[]>([]);
|
43 | 46 | let shouldAnimate = writable<boolean>(false);
|
44 |
| - const PROVIDERS_CACHE_PREFIX = 'system3-relay-auth-providers-'; |
45 |
| - |
| 47 | + const PROVIDERS_CACHE_PREFIX = "system3-relay-auth-providers-"; |
| 48 | +
|
46 | 49 | function getCacheKey(): string {
|
47 | 50 | // Use the PocketBase URL as the cache key
|
48 |
| - const pbUrl = lm.pb?.baseUrl || 'default'; |
| 51 | + const pbUrl = lm.pb?.baseUrl || "default"; |
49 | 52 | return `${PROVIDERS_CACHE_PREFIX}${pbUrl}`;
|
50 | 53 | }
|
51 |
| - |
| 54 | +
|
52 | 55 | function getDefaultProviders(): string[] {
|
53 | 56 | const defaults = ["google", "microsoft"];
|
54 |
| - |
| 57 | +
|
55 | 58 | if ($flagManager.getFlag("enableDiscordLogin")) {
|
56 | 59 | defaults.push("discord");
|
57 | 60 | }
|
58 | 61 | if ($flagManager.getFlag("enableGitHubLogin")) {
|
59 | 62 | defaults.push("github");
|
60 | 63 | }
|
61 | 64 | // OIDC is intentionally excluded from defaults
|
62 |
| - |
| 65 | +
|
63 | 66 | return defaults;
|
64 | 67 | }
|
65 | 68 |
|
|
71 | 74 | return JSON.parse(cached);
|
72 | 75 | }
|
73 | 76 | } catch (e) {
|
74 |
| - console.error("Failed to load cached providers:", e); |
| 77 | + errorLog("Failed to load cached providers:", e); |
75 | 78 | }
|
76 | 79 | // Return default providers if no cache exists
|
77 | 80 | return getDefaultProviders();
|
78 | 81 | }
|
79 |
| - |
| 82 | +
|
80 | 83 | function saveCachedProviders(providerList: string[]) {
|
81 | 84 | try {
|
82 | 85 | const cacheKey = getCacheKey();
|
83 | 86 | localStorage.setItem(cacheKey, JSON.stringify(providerList));
|
84 | 87 | } catch (e) {
|
85 |
| - console.error("Failed to save cached providers:", e); |
| 88 | + errorLog("Failed to save cached providers:", e); |
86 | 89 | }
|
87 | 90 | }
|
88 | 91 |
|
|
104 | 107 | });
|
105 | 108 |
|
106 | 109 | const visibleProviders = derived(
|
107 |
| - [selectedProvider, lm.loginSettings, flagManager, hasProviderInfo, cachedProviders], |
| 110 | + [ |
| 111 | + selectedProvider, |
| 112 | + lm.loginSettings, |
| 113 | + flagManager, |
| 114 | + hasProviderInfo, |
| 115 | + cachedProviders, |
| 116 | + ], |
108 | 117 | () => {
|
109 | 118 | // First check the loginSettings store
|
110 | 119 | if ($loginSettings && $loginSettings.provider)
|
111 | 120 | return [$loginSettings.provider];
|
112 | 121 |
|
113 | 122 | // Fall back to selectedProvider for compatibility
|
114 | 123 | if ($selectedProvider !== "") return [$selectedProvider];
|
115 |
| - |
| 124 | +
|
116 | 125 | // If we have provider info from the API, only show those that are available
|
117 | 126 | if ($hasProviderInfo && Object.keys(providers).length > 0) {
|
118 | 127 | // Filter to only show providers that were returned from the API
|
119 | 128 | const availableFromApi = Object.keys(providers);
|
120 | 129 | const visible = [];
|
121 |
| - |
| 130 | +
|
122 | 131 | // Check each provider in preferred order
|
123 | 132 | if (availableFromApi.includes("google")) {
|
124 | 133 | visible.push("google");
|
125 | 134 | }
|
126 | 135 | if (availableFromApi.includes("microsoft")) {
|
127 | 136 | visible.push("microsoft");
|
128 | 137 | }
|
129 |
| - if (availableFromApi.includes("discord") && $flagManager.getFlag("enableDiscordLogin")) { |
| 138 | + if ( |
| 139 | + availableFromApi.includes("discord") && |
| 140 | + $flagManager.getFlag("enableDiscordLogin") |
| 141 | + ) { |
130 | 142 | visible.push("discord");
|
131 | 143 | }
|
132 |
| - if (availableFromApi.includes("github") && $flagManager.getFlag("enableGitHubLogin")) { |
| 144 | + if ( |
| 145 | + availableFromApi.includes("github") && |
| 146 | + $flagManager.getFlag("enableGitHubLogin") |
| 147 | + ) { |
133 | 148 | visible.push("github");
|
134 | 149 | }
|
135 |
| - |
| 150 | +
|
136 | 151 | // Include any OIDC providers (oidc, oidc2, oidc-custom, etc.) if feature flag is enabled
|
137 |
| - availableFromApi.forEach(provider => { |
138 |
| - if (provider.startsWith("oidc") && $flagManager.getFlag("enableOIDCLogin")) { |
| 152 | + availableFromApi.forEach((provider) => { |
| 153 | + if ( |
| 154 | + provider.startsWith("oidc") && |
| 155 | + $flagManager.getFlag("enableOIDCLogin") |
| 156 | + ) { |
139 | 157 | visible.push(provider);
|
140 | 158 | }
|
141 | 159 | });
|
142 |
| - |
| 160 | +
|
143 | 161 | // Check if the list has changed from what we expected (cached or defaults)
|
144 |
| - const hasChanged = JSON.stringify(visible.sort()) !== JSON.stringify($cachedProviders.sort()); |
| 162 | + const hasChanged = |
| 163 | + JSON.stringify(visible.sort()) !== |
| 164 | + JSON.stringify($cachedProviders.sort()); |
145 | 165 | shouldAnimate.set(hasChanged);
|
146 |
| - |
| 166 | +
|
147 | 167 | // Save to cache for next time
|
148 | 168 | saveCachedProviders(visible);
|
149 |
| - |
| 169 | +
|
150 | 170 | return visible;
|
151 | 171 | }
|
152 |
| - |
| 172 | +
|
153 | 173 | // If we have cached providers and no API info yet, use the cache
|
154 | 174 | if ($cachedProviders.length > 0 && !$hasProviderInfo) {
|
155 | 175 | return $cachedProviders;
|
156 | 176 | }
|
157 |
| - |
| 177 | +
|
158 | 178 | // Default behavior if no provider info yet or request failed
|
159 | 179 | const visible = ["google", "microsoft"];
|
160 | 180 |
|
|
188 | 208 | const names: Record<string, string> = {};
|
189 | 209 | for (const providerName of Object.keys(providers)) {
|
190 | 210 | const provider = providers[providerName];
|
191 |
| - |
| 211 | +
|
192 | 212 | if (provider?.info?.displayName) {
|
193 | 213 | names[providerName] = provider.info.displayName;
|
194 | 214 | } else {
|
|
298 | 318 |
|
299 | 319 | function capitalize(s: string): string {
|
300 | 320 | if (!s) return "";
|
301 |
| - if (s == "oidc") return "OIDC"; |
302 |
| - if (s == "github") return "GitHub"; |
| 321 | + if (s == "oidc") return "OIDC"; |
| 322 | + if (s == "github") return "GitHub"; |
303 | 323 | return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
|
304 | 324 | }
|
305 |
| -
|
306 | 325 | </script>
|
307 | 326 |
|
308 | 327 | {#if $lm.hasUser && $lm.user}
|
|
326 | 345 | <div class="login-buttons">
|
327 | 346 | {#each $visibleProviders as provider (provider)}
|
328 | 347 | <button
|
329 |
| - class={`${provider.startsWith('oidc') ? 'oidc' : provider}-sign-in-button`} |
| 348 | + class={`${provider.startsWith("oidc") ? "oidc" : provider}-sign-in-button`} |
330 | 349 | disabled={$pending || !$configuredProviders.contains(provider)}
|
331 |
| - transition:slide={{ duration: $shouldAnimate ? 300 : 0, easing: quintOut }} |
| 350 | + transition:slide={{ |
| 351 | + duration: $shouldAnimate ? 300 : 0, |
| 352 | + easing: quintOut, |
| 353 | + }} |
332 | 354 | on:click={debounce(async () => {
|
333 | 355 | pending.set(true);
|
334 | 356 | await login(provider);
|
335 |
| - })}>Sign in with {$providerDisplayNames[provider] || capitalize(provider)}</button |
| 357 | + })} |
| 358 | + >Sign in with {$providerDisplayNames[provider] || |
| 359 | + capitalize(provider)}</button |
336 | 360 | >
|
337 | 361 | {/each}
|
338 | 362 | </div>
|
|
342 | 366 | {#if providers[provider]}
|
343 | 367 | <a href={providers[provider].fullAuthUrl} target="_blank">
|
344 | 368 | <button
|
345 |
| - class={`${provider.startsWith('oidc') ? 'oidc' : provider}-sign-in-button`} |
| 369 | + class={`${provider.startsWith("oidc") ? "oidc" : provider}-sign-in-button`} |
346 | 370 | disabled={$pending || !providers[provider]}
|
347 |
| - transition:slide={{ duration: $shouldAnimate ? 300 : 0, easing: quintOut }} |
| 371 | + transition:slide={{ |
| 372 | + duration: $shouldAnimate ? 300 : 0, |
| 373 | + easing: quintOut, |
| 374 | + }} |
348 | 375 | on:click={() => {
|
349 | 376 | pending.set(true);
|
350 | 377 | poll(provider);
|
351 |
| - }}>Sign in with {$providerDisplayNames[provider] || capitalize(provider)}</button |
| 378 | + }} |
| 379 | + >Sign in with {$providerDisplayNames[provider] || |
| 380 | + capitalize(provider)}</button |
352 | 381 | >
|
353 | 382 | </a>
|
354 | 383 | {:else}
|
355 |
| - <button |
356 |
| - class={`${provider.startsWith('oidc') ? 'oidc' : provider}-sign-in-button`} |
| 384 | + <button |
| 385 | + class={`${provider.startsWith("oidc") ? "oidc" : provider}-sign-in-button`} |
357 | 386 | disabled={true}
|
358 |
| - transition:slide={{ duration: $shouldAnimate ? 300 : 0, easing: quintOut }} |
359 |
| - >Sign in with {$providerDisplayNames[provider] || capitalize(provider)}</button |
| 387 | + transition:slide={{ |
| 388 | + duration: $shouldAnimate ? 300 : 0, |
| 389 | + easing: quintOut, |
| 390 | + }} |
| 391 | + >Sign in with {$providerDisplayNames[provider] || |
| 392 | + capitalize(provider)}</button |
360 | 393 | >
|
361 | 394 | {/if}
|
362 | 395 | {/each}
|
|
0 commit comments