@sourceregistry/sveltekit-oidc 1.6.7 → 1.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@
6
6
  </script>
7
7
 
8
8
  <script lang="ts" generics="TClaims extends OIDCUserClaims = OIDCUserClaims">
9
- import {invalidateAll} from '$app/navigation';
9
+ import {invalidateAll, beforeNavigate} from '$app/navigation';
10
10
  import {tick} from 'svelte';
11
11
  import type {Snippet} from 'svelte';
12
12
 
@@ -44,6 +44,7 @@
44
44
 
45
45
  let iframe = $state<HTMLIFrameElement | undefined>(undefined);
46
46
  let status = $state<'authenticated' | 'unauthenticated' | 'expired' | 'revoked'>('unauthenticated');
47
+ let revalidating = $state(false);
47
48
  let handledUnauthenticated = $state(false);
48
49
 
49
50
  const metadata = $derived(config.metadata);
@@ -77,6 +78,9 @@
77
78
  get status() {
78
79
  return status;
79
80
  },
81
+ get revalidating() {
82
+ return revalidating;
83
+ },
80
84
  login: (returnTo?: string) => login(returnTo),
81
85
  logout,
82
86
  revalidate
@@ -110,7 +114,32 @@
110
114
  }
111
115
 
112
116
  async function revalidate() {
113
- await invalidateAll();
117
+ if (revalidating) return;
118
+ revalidating = true;
119
+
120
+ // If the server redirects to the login path during a background
121
+ // revalidation (e.g. session lost, HMR store reset), intercept the
122
+ // SvelteKit router navigation so we can handle it through
123
+ // handleRedirect instead of a jarring mid-page router transition.
124
+ let sessionExpiredDuringRevalidation = false;
125
+ const stopIntercept = beforeNavigate(({ to, cancel }) => {
126
+ if (to?.url.pathname.startsWith(resolvedLoginPath)) {
127
+ cancel();
128
+ sessionExpiredDuringRevalidation = true;
129
+ }
130
+ });
131
+
132
+ try {
133
+ await invalidateAll();
134
+ } finally {
135
+ stopIntercept();
136
+ revalidating = false;
137
+ }
138
+
139
+ if (sessionExpiredDuringRevalidation) {
140
+ status = 'expired';
141
+ void handleRedirect(redirectOnExpired);
142
+ }
114
143
  }
115
144
 
116
145
  async function handleRedirect(mode: RedirectMode) {
@@ -132,6 +161,10 @@
132
161
 
133
162
  $effect(() => {
134
163
  const isAuthenticated = Boolean(session?.isAuthenticated);
164
+ // Suppress authenticated→unauthenticated transition while a revalidation is
165
+ // in-flight — the effect re-runs once revalidating flips false with the
166
+ // final session state, preventing a mid-refresh flicker.
167
+ if (revalidating && !isAuthenticated) return;
135
168
  status = isAuthenticated ? 'authenticated' : status === 'authenticated' ? 'unauthenticated' : status;
136
169
  });
137
170
 
@@ -10,6 +10,7 @@ export type OIDCClientContextValue<TClaims extends OIDCUserClaims = OIDCUserClai
10
10
  groups: OIDCPublicSession<TClaims>['groups'];
11
11
  metadata?: Pick<OIDCDiscoveryDocument, 'issuer' | 'check_session_iframe' | 'end_session_endpoint' | 'backchannel_logout_supported' | 'backchannel_logout_session_supported'>;
12
12
  status: 'authenticated' | 'unauthenticated' | 'expired' | 'revoked';
13
+ revalidating: boolean;
13
14
  login: (returnTo?: string) => void;
14
15
  logout: (clearSessionOnly?: boolean) => Promise<void>;
15
16
  revalidate: () => Promise<void>;
@@ -479,7 +479,7 @@ export function createOIDC(options) {
479
479
  };
480
480
  async function hook(event) {
481
481
  const session = await getSession(event);
482
- return event.locals.oidc = {
482
+ const locals = {
483
483
  oidc: {
484
484
  isAuthenticated: Boolean(session),
485
485
  session,
@@ -494,6 +494,8 @@ export function createOIDC(options) {
494
494
  clearSession: async () => clearPersistedSession(event.cookies)
495
495
  }
496
496
  };
497
+ event.locals.oidc = locals.oidc;
498
+ return locals;
497
499
  }
498
500
  function loginHandler(defaults = {}) {
499
501
  return async (event) => {
@@ -17,7 +17,10 @@ export function createInMemoryBackChannelLogoutStore() {
17
17
  };
18
18
  }
19
19
  export function createInMemorySessionStore() {
20
- const sessions = new Map();
20
+ // Persist the Map on globalThis so Vite HMR module re-evaluations don't
21
+ // create a fresh store and orphan all live session cookies.
22
+ const g = globalThis;
23
+ const sessions = (g['__oidc_sessions__'] ??= new Map());
21
24
  return {
22
25
  async get(sessionId) {
23
26
  return sessions.get(sessionId) ?? null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sourceregistry/sveltekit-oidc",
3
- "version": "1.6.7",
3
+ "version": "1.6.9",
4
4
  "description": "OIDC authentication helpers for SvelteKit applications",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {