@supabase/auth-js 2.117.0 → 2.117.1
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.
- package/dist/main/GoTrueClient.d.ts +7 -0
- package/dist/main/GoTrueClient.d.ts.map +1 -1
- package/dist/main/GoTrueClient.js +45 -40
- package/dist/main/GoTrueClient.js.map +1 -1
- package/dist/main/lib/version.d.ts +1 -1
- package/dist/main/lib/version.js +1 -1
- package/dist/module/GoTrueClient.d.ts +7 -0
- package/dist/module/GoTrueClient.d.ts.map +1 -1
- package/dist/module/GoTrueClient.js +45 -40
- package/dist/module/GoTrueClient.js.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.js +1 -1
- package/dist/tsconfig.module.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/migrations/lockless-coordination.md +3 -3
- package/package.json +1 -1
- package/src/GoTrueClient.ts +55 -50
- package/src/lib/version.ts +1 -1
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
## What changed
|
|
9
9
|
|
|
10
10
|
- **Default coordination is lockless.** A client constructed without a `lock` option no longer acquires `navigator.locks` or any in-process lock. In-tab concurrent refreshes are deduplicated via the pre-existing single-flight (`refreshingDeferred`); cross-tab refresh races are resolved by GoTrue's server-side parent-of-active mechanism on the v1 refresh-token path.
|
|
11
|
-
- **Commit guard inside `_callRefreshToken`.** The client snapshots storage before the rotated-token fetch and re-reads after. If a non-null pre-fetch snapshot was cleared between the two reads (
|
|
12
|
-
- **New `AuthRefreshDiscardedError`** (with `isAuthRefreshDiscardedError` type guard). Surfaces through `refreshSession()` and `
|
|
11
|
+
- **Commit guard inside `_callRefreshToken`.** The client snapshots storage before the rotated-token fetch and re-reads after. If a non-null pre-fetch snapshot was cleared or replaced between the two reads (a concurrent `signOut` ran `_removeSession`, or another tab's refresh rotated first), the rotated tokens are discarded instead of being written back over storage. The discarded result resolves with `{ data: null, error: new AuthRefreshDiscardedError() }`.
|
|
12
|
+
- **New `AuthRefreshDiscardedError`** (with `isAuthRefreshDiscardedError` type guard). Surfaces through `refreshSession()` and `setSession()` results when the commit guard fires. `getSession()` surfaces it only when storage was cleared mid-flight; when another caller's rotation replaced storage, `getSession()` returns the session now in storage instead. Distinct from `AuthRetryableFetchError` (transient network) and `AuthApiError` (server rejection).
|
|
13
13
|
- **New `client.auth.dispose()`.** Tears down the auto-refresh interval, the `visibilitychange` listener, the `BroadcastChannel`, and registered `onAuthStateChange` subscribers. Idempotent. Designed for React Strict Mode and HMR cleanup hooks. In-flight `fetch` calls are not aborted — they run to completion.
|
|
14
14
|
- **`lock` and `lockAcquireTimeout` options.** Accepted and honored when supplied (legacy opt-in path); both are `@deprecated` and will be removed in v3.
|
|
15
15
|
|
|
@@ -39,7 +39,7 @@ useEffect(() => {
|
|
|
39
39
|
|
|
40
40
|
### `AuthRefreshDiscardedError`
|
|
41
41
|
|
|
42
|
-
Returned from `refreshSession()` / `
|
|
42
|
+
Returned from `refreshSession()` / `setSession()` when the commit guard discards a successfully-rotated session. `getSession()` returns it only when storage was cleared mid-flight (concurrent `signOut`); when another tab's refresh replaced storage, `getSession()` hands back that session instead.
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
45
|
import { isAuthRefreshDiscardedError } from '@supabase/auth-js'
|
package/package.json
CHANGED
package/src/GoTrueClient.ts
CHANGED
|
@@ -3075,60 +3075,36 @@ export default class GoTrueClient {
|
|
|
3075
3075
|
)
|
|
3076
3076
|
|
|
3077
3077
|
if (!hasExpired) {
|
|
3078
|
-
|
|
3079
|
-
const maybeUser: { user?: User | null } | null = (await getItemAsync(
|
|
3080
|
-
this.userStorage,
|
|
3081
|
-
this.storageKey + '-user'
|
|
3082
|
-
)) as any
|
|
3083
|
-
|
|
3084
|
-
if (maybeUser?.user) {
|
|
3085
|
-
currentSession.user = maybeUser.user
|
|
3086
|
-
} else {
|
|
3087
|
-
currentSession.user = userNotAvailableProxy()
|
|
3088
|
-
}
|
|
3089
|
-
}
|
|
3090
|
-
|
|
3091
|
-
// Wrap the user object with a warning proxy on the server
|
|
3092
|
-
// This warns when properties of the user are accessed, not when session.user itself is accessed
|
|
3093
|
-
if (
|
|
3094
|
-
this.storage.isServer &&
|
|
3095
|
-
currentSession.user &&
|
|
3096
|
-
!(currentSession.user as any).__isUserNotAvailableProxy
|
|
3097
|
-
) {
|
|
3098
|
-
const suppressWarningRef = { value: this.suppressGetSessionWarning }
|
|
3099
|
-
currentSession.user = insecureUserWarningProxy(currentSession.user, suppressWarningRef)
|
|
3100
|
-
|
|
3101
|
-
// Update the client-level suppression flag when the proxy suppresses the warning
|
|
3102
|
-
if (suppressWarningRef.value) {
|
|
3103
|
-
this.suppressGetSessionWarning = true
|
|
3104
|
-
}
|
|
3105
|
-
}
|
|
3106
|
-
|
|
3107
|
-
return { data: { session: currentSession }, error: null }
|
|
3078
|
+
return { data: { session: await this._hydrateSessionUser(currentSession) }, error: null }
|
|
3108
3079
|
}
|
|
3109
3080
|
|
|
3110
3081
|
const { data: session, error } = await this._callRefreshToken(currentSession.refresh_token)
|
|
3111
3082
|
if (error) {
|
|
3112
|
-
//
|
|
3113
|
-
//
|
|
3114
|
-
//
|
|
3115
|
-
// still
|
|
3116
|
-
//
|
|
3117
|
-
//
|
|
3118
|
-
// refresh
|
|
3119
|
-
//
|
|
3120
|
-
//
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3083
|
+
// A failed refresh does not mean there is no session. Storage is the
|
|
3084
|
+
// source of truth at this point, because either:
|
|
3085
|
+
// - `_callRefreshToken` kept the original session in storage since
|
|
3086
|
+
// the access token is still inside its real expiry window (a
|
|
3087
|
+
// proactive refresh that failed non-retryably), or
|
|
3088
|
+
// - another caller, in this tab or a different one, committed its
|
|
3089
|
+
// own rotated session while this refresh was in flight, so this
|
|
3090
|
+
// one was discarded by the commit guard or rejected by the server
|
|
3091
|
+
// as already used.
|
|
3092
|
+
// Empty storage (concurrent `signOut`) or an expired stored session
|
|
3093
|
+
// means the session is genuinely gone and the error stands. Callers
|
|
3094
|
+
// that pass an explicit token (`setSession`,
|
|
3095
|
+
// `refreshSession({ refresh_token })`) call `_callRefreshToken`
|
|
3096
|
+
// directly and surface the failure instead.
|
|
3097
|
+
const stored = (await getItemAsync(this.storage, this.storageKey)) as Session | null
|
|
3098
|
+
if (
|
|
3099
|
+
stored &&
|
|
3100
|
+
this._isValidSession(stored) &&
|
|
3101
|
+
stored.expires_at &&
|
|
3102
|
+
stored.expires_at * 1000 > Date.now()
|
|
3103
|
+
) {
|
|
3104
|
+
return this._returnResult({
|
|
3105
|
+
data: { session: await this._hydrateSessionUser(stored) },
|
|
3106
|
+
error: null,
|
|
3107
|
+
})
|
|
3132
3108
|
}
|
|
3133
3109
|
return this._returnResult({ data: { session: null }, error })
|
|
3134
3110
|
}
|
|
@@ -3139,6 +3115,35 @@ export default class GoTrueClient {
|
|
|
3139
3115
|
}
|
|
3140
3116
|
}
|
|
3141
3117
|
|
|
3118
|
+
/**
|
|
3119
|
+
* Completes a session read back from storage so it matches what callers of
|
|
3120
|
+
* `getSession()` expect: fills in `session.user` from `userStorage` when the
|
|
3121
|
+
* client keeps the user in split storage, and wraps the user in the
|
|
3122
|
+
* insecure-access warning proxy on the server.
|
|
3123
|
+
*/
|
|
3124
|
+
private async _hydrateSessionUser(session: Session): Promise<Session> {
|
|
3125
|
+
if (this.userStorage) {
|
|
3126
|
+
const maybeUser: { user?: User | null } | null = (await getItemAsync(
|
|
3127
|
+
this.userStorage,
|
|
3128
|
+
this.storageKey + '-user'
|
|
3129
|
+
)) as any
|
|
3130
|
+
|
|
3131
|
+
session.user = maybeUser?.user ? maybeUser.user : userNotAvailableProxy()
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3134
|
+
// Warns when properties of the user are accessed, not when session.user itself is accessed.
|
|
3135
|
+
if (this.storage.isServer && session.user && !(session.user as any).__isUserNotAvailableProxy) {
|
|
3136
|
+
const suppressWarningRef = { value: this.suppressGetSessionWarning }
|
|
3137
|
+
session.user = insecureUserWarningProxy(session.user, suppressWarningRef)
|
|
3138
|
+
|
|
3139
|
+
if (suppressWarningRef.value) {
|
|
3140
|
+
this.suppressGetSessionWarning = true
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
return session
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3142
3147
|
/**
|
|
3143
3148
|
* Gets the current user details if there is an existing session. This method
|
|
3144
3149
|
* performs a network request to the Supabase Auth server, so the returned
|
package/src/lib/version.ts
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
// - Debugging and support (identifying which version is running)
|
|
5
5
|
// - Telemetry and logging (version reporting in errors/analytics)
|
|
6
6
|
// - Ensuring build artifacts match the published package version
|
|
7
|
-
export const version = '2.117.
|
|
7
|
+
export const version = '2.117.1'
|