@supabase/gotrue-js 2.46.2 → 2.47.0
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 +19 -1
- package/dist/main/GoTrueClient.d.ts.map +1 -1
- package/dist/main/GoTrueClient.js +179 -103
- package/dist/main/GoTrueClient.js.map +1 -1
- package/dist/main/lib/helpers.d.ts +0 -29
- package/dist/main/lib/helpers.d.ts.map +1 -1
- package/dist/main/lib/helpers.js +1 -117
- package/dist/main/lib/helpers.js.map +1 -1
- package/dist/main/lib/locks.d.ts.map +1 -1
- package/dist/main/lib/locks.js +16 -58
- package/dist/main/lib/locks.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 +19 -1
- package/dist/module/GoTrueClient.d.ts.map +1 -1
- package/dist/module/GoTrueClient.js +180 -104
- package/dist/module/GoTrueClient.js.map +1 -1
- package/dist/module/lib/helpers.d.ts +0 -29
- package/dist/module/lib/helpers.d.ts.map +1 -1
- package/dist/module/lib/helpers.js +0 -113
- package/dist/module/lib/helpers.js.map +1 -1
- package/dist/module/lib/locks.d.ts.map +1 -1
- package/dist/module/lib/locks.js +16 -58
- package/dist/module/lib/locks.js.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/GoTrueClient.ts +235 -135
- package/src/lib/helpers.ts +0 -140
- package/src/lib/locks.ts +17 -73
- package/src/lib/version.ts +1 -1
package/src/GoTrueClient.ts
CHANGED
|
@@ -28,9 +28,6 @@ import {
|
|
|
28
28
|
generatePKCEVerifier,
|
|
29
29
|
generatePKCEChallenge,
|
|
30
30
|
supportsLocalStorage,
|
|
31
|
-
stackGuard,
|
|
32
|
-
isInStackGuard,
|
|
33
|
-
stackGuardsSupported,
|
|
34
31
|
parseParametersFromURL,
|
|
35
32
|
} from './lib/helpers'
|
|
36
33
|
import localStorageAdapter from './lib/local-storage'
|
|
@@ -154,6 +151,8 @@ export default class GoTrueClient {
|
|
|
154
151
|
}
|
|
155
152
|
protected fetch: Fetch
|
|
156
153
|
protected lock: LockFunc
|
|
154
|
+
protected lockAcquired = false
|
|
155
|
+
protected pendingInLock: Promise<any>[] = []
|
|
157
156
|
|
|
158
157
|
/**
|
|
159
158
|
* Used to broadcast state change events to other tabs listening.
|
|
@@ -248,12 +247,18 @@ export default class GoTrueClient {
|
|
|
248
247
|
* This method is automatically called when instantiating the client, but should also be called
|
|
249
248
|
* manually when checking for an error from an auth redirect (oauth, magiclink, password recovery, etc).
|
|
250
249
|
*/
|
|
251
|
-
initialize(): Promise<InitializeResult> {
|
|
250
|
+
async initialize(): Promise<InitializeResult> {
|
|
252
251
|
if (this.initializePromise) {
|
|
253
|
-
return this.initializePromise
|
|
252
|
+
return await this.initializePromise
|
|
254
253
|
}
|
|
255
254
|
|
|
256
|
-
|
|
255
|
+
this.initializePromise = (async () => {
|
|
256
|
+
return await this._acquireLock(-1, async () => {
|
|
257
|
+
return await this._initialize()
|
|
258
|
+
})
|
|
259
|
+
})()
|
|
260
|
+
|
|
261
|
+
return await this.initializePromise
|
|
257
262
|
}
|
|
258
263
|
|
|
259
264
|
/**
|
|
@@ -263,71 +268,59 @@ export default class GoTrueClient {
|
|
|
263
268
|
* the whole lifetime of the client
|
|
264
269
|
*/
|
|
265
270
|
private async _initialize(): Promise<InitializeResult> {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
this.initializePromise = this._acquireLock(
|
|
271
|
-
-1,
|
|
272
|
-
async () =>
|
|
273
|
-
await stackGuard('_initialize', async () => {
|
|
274
|
-
try {
|
|
275
|
-
const isPKCEFlow = isBrowser() ? await this._isPKCEFlow() : false
|
|
276
|
-
this._debug('#_initialize()', 'begin', 'is PKCE flow', isPKCEFlow)
|
|
277
|
-
|
|
278
|
-
if (isPKCEFlow || (this.detectSessionInUrl && this._isImplicitGrantFlow())) {
|
|
279
|
-
const { data, error } = await this._getSessionFromURL(isPKCEFlow)
|
|
280
|
-
if (error) {
|
|
281
|
-
this._debug('#_initialize()', 'error detecting session from URL', error)
|
|
282
|
-
|
|
283
|
-
// failed login attempt via url,
|
|
284
|
-
// remove old session as in verifyOtp, signUp and signInWith*
|
|
285
|
-
await this._removeSession()
|
|
271
|
+
try {
|
|
272
|
+
const isPKCEFlow = isBrowser() ? await this._isPKCEFlow() : false
|
|
273
|
+
this._debug('#_initialize()', 'begin', 'is PKCE flow', isPKCEFlow)
|
|
286
274
|
|
|
287
|
-
|
|
288
|
-
|
|
275
|
+
if (isPKCEFlow || (this.detectSessionInUrl && this._isImplicitGrantFlow())) {
|
|
276
|
+
const { data, error } = await this._getSessionFromURL(isPKCEFlow)
|
|
277
|
+
if (error) {
|
|
278
|
+
this._debug('#_initialize()', 'error detecting session from URL', error)
|
|
289
279
|
|
|
290
|
-
|
|
280
|
+
// failed login attempt via url,
|
|
281
|
+
// remove old session as in verifyOtp, signUp and signInWith*
|
|
282
|
+
await this._removeSession()
|
|
291
283
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
'detected session in URL',
|
|
295
|
-
session,
|
|
296
|
-
'redirect type',
|
|
297
|
-
redirectType
|
|
298
|
-
)
|
|
284
|
+
return { error }
|
|
285
|
+
}
|
|
299
286
|
|
|
300
|
-
|
|
287
|
+
const { session, redirectType } = data
|
|
301
288
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
289
|
+
this._debug(
|
|
290
|
+
'#_initialize()',
|
|
291
|
+
'detected session in URL',
|
|
292
|
+
session,
|
|
293
|
+
'redirect type',
|
|
294
|
+
redirectType
|
|
295
|
+
)
|
|
309
296
|
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
// no login attempt via callback url try to recover session from storage
|
|
313
|
-
await this._recoverAndRefresh()
|
|
314
|
-
return { error: null }
|
|
315
|
-
} catch (error) {
|
|
316
|
-
if (isAuthError(error)) {
|
|
317
|
-
return { error }
|
|
318
|
-
}
|
|
297
|
+
await this._saveSession(session)
|
|
319
298
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
await this.
|
|
325
|
-
this._debug('#_initialize()', 'end')
|
|
299
|
+
setTimeout(async () => {
|
|
300
|
+
if (redirectType === 'recovery') {
|
|
301
|
+
await this._notifyAllSubscribers('PASSWORD_RECOVERY', session)
|
|
302
|
+
} else {
|
|
303
|
+
await this._notifyAllSubscribers('SIGNED_IN', session)
|
|
326
304
|
}
|
|
327
|
-
})
|
|
328
|
-
)
|
|
305
|
+
}, 0)
|
|
329
306
|
|
|
330
|
-
|
|
307
|
+
return { error: null }
|
|
308
|
+
}
|
|
309
|
+
// no login attempt via callback url try to recover session from storage
|
|
310
|
+
await this._recoverAndRefresh()
|
|
311
|
+
return { error: null }
|
|
312
|
+
} catch (error) {
|
|
313
|
+
if (isAuthError(error)) {
|
|
314
|
+
return { error }
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
error: new AuthUnknownError('Unexpected error during initialization', error),
|
|
319
|
+
}
|
|
320
|
+
} finally {
|
|
321
|
+
await this._handleVisibilityChange()
|
|
322
|
+
this._debug('#_initialize()', 'end')
|
|
323
|
+
}
|
|
331
324
|
}
|
|
332
325
|
|
|
333
326
|
/**
|
|
@@ -490,6 +483,14 @@ export default class GoTrueClient {
|
|
|
490
483
|
* Log in an existing user by exchanging an Auth Code issued during the PKCE flow.
|
|
491
484
|
*/
|
|
492
485
|
async exchangeCodeForSession(authCode: string): Promise<AuthTokenResponse> {
|
|
486
|
+
await this.initializePromise
|
|
487
|
+
|
|
488
|
+
return this._acquireLock(-1, async () => {
|
|
489
|
+
return this._exchangeCodeForSession(authCode)
|
|
490
|
+
})
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
private async _exchangeCodeForSession(authCode: string): Promise<AuthTokenResponse> {
|
|
493
494
|
const codeVerifier = await getItemAsync(this.storage, `${this.storageKey}-code-verifier`)
|
|
494
495
|
const { data, error } = await _request(
|
|
495
496
|
this.fetch,
|
|
@@ -726,6 +727,14 @@ export default class GoTrueClient {
|
|
|
726
727
|
* Requires the user to be signed-in.
|
|
727
728
|
*/
|
|
728
729
|
async reauthenticate(): Promise<AuthResponse> {
|
|
730
|
+
await this.initializePromise
|
|
731
|
+
|
|
732
|
+
return await this._acquireLock(-1, async () => {
|
|
733
|
+
return await this._reauthenticate()
|
|
734
|
+
})
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
private async _reauthenticate(): Promise<AuthResponse> {
|
|
729
738
|
try {
|
|
730
739
|
return await this._useSession(async (result) => {
|
|
731
740
|
const {
|
|
@@ -799,8 +808,12 @@ export default class GoTrueClient {
|
|
|
799
808
|
* The session returned can be null if the session is not detected which can happen in the event a user is not signed-in or has logged out.
|
|
800
809
|
*/
|
|
801
810
|
async getSession() {
|
|
802
|
-
|
|
803
|
-
|
|
811
|
+
await this.initializePromise
|
|
812
|
+
|
|
813
|
+
return this._acquireLock(-1, async () => {
|
|
814
|
+
return this._useSession(async (result) => {
|
|
815
|
+
return result
|
|
816
|
+
})
|
|
804
817
|
})
|
|
805
818
|
}
|
|
806
819
|
|
|
@@ -811,29 +824,63 @@ export default class GoTrueClient {
|
|
|
811
824
|
this._debug('#_acquireLock', 'begin', acquireTimeout)
|
|
812
825
|
|
|
813
826
|
try {
|
|
814
|
-
if (
|
|
815
|
-
this.
|
|
816
|
-
|
|
817
|
-
|
|
827
|
+
if (this.lockAcquired) {
|
|
828
|
+
const last = this.pendingInLock.length
|
|
829
|
+
? this.pendingInLock[this.pendingInLock.length - 1]
|
|
830
|
+
: Promise.resolve()
|
|
831
|
+
|
|
832
|
+
const result = (async () => {
|
|
833
|
+
await last
|
|
834
|
+
return await fn()
|
|
835
|
+
})()
|
|
836
|
+
|
|
837
|
+
this.pendingInLock.push(
|
|
838
|
+
(async () => {
|
|
839
|
+
try {
|
|
840
|
+
await result
|
|
841
|
+
} catch (e: any) {
|
|
842
|
+
// we jsut care if it finished
|
|
843
|
+
}
|
|
844
|
+
})()
|
|
818
845
|
)
|
|
819
846
|
|
|
820
|
-
return
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
if (isInStackGuard('_acquireLock')) {
|
|
824
|
-
this._debug('#_acquireLock', 'recursive call')
|
|
825
|
-
return await fn()
|
|
847
|
+
return result
|
|
826
848
|
}
|
|
827
849
|
|
|
828
850
|
return await this.lock(`lock:${this.storageKey}`, acquireTimeout, async () => {
|
|
829
851
|
this._debug('#_acquireLock', 'lock acquired for storage key', this.storageKey)
|
|
830
852
|
|
|
831
853
|
try {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
854
|
+
this.lockAcquired = true
|
|
855
|
+
|
|
856
|
+
const result = fn()
|
|
857
|
+
|
|
858
|
+
this.pendingInLock.push(
|
|
859
|
+
(async () => {
|
|
860
|
+
try {
|
|
861
|
+
await result
|
|
862
|
+
} catch (e: any) {
|
|
863
|
+
// we just care if it finished
|
|
864
|
+
}
|
|
865
|
+
})()
|
|
866
|
+
)
|
|
867
|
+
|
|
868
|
+
await result
|
|
869
|
+
|
|
870
|
+
// keep draining the queue until there's nothing to wait on
|
|
871
|
+
while (this.pendingInLock.length) {
|
|
872
|
+
const waitOn = [...this.pendingInLock]
|
|
873
|
+
|
|
874
|
+
await Promise.all(waitOn)
|
|
875
|
+
|
|
876
|
+
this.pendingInLock.splice(0, waitOn.length)
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
return await result
|
|
835
880
|
} finally {
|
|
836
881
|
this._debug('#_acquireLock', 'lock released for storage key', this.storageKey)
|
|
882
|
+
|
|
883
|
+
this.lockAcquired = false
|
|
837
884
|
}
|
|
838
885
|
})
|
|
839
886
|
} finally {
|
|
@@ -873,23 +920,10 @@ export default class GoTrueClient {
|
|
|
873
920
|
this._debug('#_useSession', 'begin')
|
|
874
921
|
|
|
875
922
|
try {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
// the use of __loadSession here is the only correct use of the function!
|
|
880
|
-
const result = await this.__loadSession()
|
|
923
|
+
// the use of __loadSession here is the only correct use of the function!
|
|
924
|
+
const result = await this.__loadSession()
|
|
881
925
|
|
|
882
|
-
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
return await this._acquireLock(-1, async () => {
|
|
886
|
-
return await stackGuard('_useSession', async () => {
|
|
887
|
-
// the use of __loadSession here is the only correct use of the function!
|
|
888
|
-
const result = await this.__loadSession()
|
|
889
|
-
|
|
890
|
-
return await fn(result)
|
|
891
|
-
})
|
|
892
|
-
})
|
|
926
|
+
return await fn(result)
|
|
893
927
|
} finally {
|
|
894
928
|
this._debug('#_useSession', 'end')
|
|
895
929
|
}
|
|
@@ -922,18 +956,10 @@ export default class GoTrueClient {
|
|
|
922
956
|
> {
|
|
923
957
|
this._debug('#__loadSession()', 'begin')
|
|
924
958
|
|
|
925
|
-
if (this.
|
|
926
|
-
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
if (isInStackGuard('_initialize')) {
|
|
930
|
-
this._debug('#__loadSession', '#_initialize recursion detected', new Error().stack)
|
|
959
|
+
if (!this.lockAcquired) {
|
|
960
|
+
this._debug('#__loadSession()', 'used outside of an acquired lock!', new Error().stack)
|
|
931
961
|
}
|
|
932
962
|
|
|
933
|
-
// always wait for #_initialize() to finish before loading anything from
|
|
934
|
-
// storage
|
|
935
|
-
await this.initializePromise
|
|
936
|
-
|
|
937
963
|
try {
|
|
938
964
|
let currentSession: Session | null = null
|
|
939
965
|
|
|
@@ -990,6 +1016,18 @@ export default class GoTrueClient {
|
|
|
990
1016
|
* @param jwt Takes in an optional access token jwt. If no jwt is provided, getUser() will attempt to get the jwt from the current session.
|
|
991
1017
|
*/
|
|
992
1018
|
async getUser(jwt?: string): Promise<UserResponse> {
|
|
1019
|
+
if (jwt) {
|
|
1020
|
+
return await this._getUser(jwt)
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
await this.initializePromise
|
|
1024
|
+
|
|
1025
|
+
return this._acquireLock(-1, async () => {
|
|
1026
|
+
return await this._getUser()
|
|
1027
|
+
})
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
private async _getUser(jwt?: string): Promise<UserResponse> {
|
|
993
1031
|
try {
|
|
994
1032
|
if (jwt) {
|
|
995
1033
|
return await _request(this.fetch, 'GET', `${this.url}/user`, {
|
|
@@ -1028,6 +1066,19 @@ export default class GoTrueClient {
|
|
|
1028
1066
|
options: {
|
|
1029
1067
|
emailRedirectTo?: string | undefined
|
|
1030
1068
|
} = {}
|
|
1069
|
+
): Promise<UserResponse> {
|
|
1070
|
+
await this.initializePromise
|
|
1071
|
+
|
|
1072
|
+
return await this._acquireLock(-1, async () => {
|
|
1073
|
+
return await this._updateUser(attributes, options)
|
|
1074
|
+
})
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
protected async _updateUser(
|
|
1078
|
+
attributes: UserAttributes,
|
|
1079
|
+
options: {
|
|
1080
|
+
emailRedirectTo?: string | undefined
|
|
1081
|
+
} = {}
|
|
1031
1082
|
): Promise<UserResponse> {
|
|
1032
1083
|
try {
|
|
1033
1084
|
return await this._useSession(async (result) => {
|
|
@@ -1081,6 +1132,17 @@ export default class GoTrueClient {
|
|
|
1081
1132
|
async setSession(currentSession: {
|
|
1082
1133
|
access_token: string
|
|
1083
1134
|
refresh_token: string
|
|
1135
|
+
}): Promise<AuthResponse> {
|
|
1136
|
+
await this.initializePromise
|
|
1137
|
+
|
|
1138
|
+
return await this._acquireLock(-1, async () => {
|
|
1139
|
+
return await this._setSession(currentSession)
|
|
1140
|
+
})
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
protected async _setSession(currentSession: {
|
|
1144
|
+
access_token: string
|
|
1145
|
+
refresh_token: string
|
|
1084
1146
|
}): Promise<AuthResponse> {
|
|
1085
1147
|
try {
|
|
1086
1148
|
if (!currentSession.access_token || !currentSession.refresh_token) {
|
|
@@ -1110,7 +1172,7 @@ export default class GoTrueClient {
|
|
|
1110
1172
|
}
|
|
1111
1173
|
session = refreshedSession
|
|
1112
1174
|
} else {
|
|
1113
|
-
const { data, error } = await this.
|
|
1175
|
+
const { data, error } = await this._getUser(currentSession.access_token)
|
|
1114
1176
|
if (error) {
|
|
1115
1177
|
throw error
|
|
1116
1178
|
}
|
|
@@ -1143,6 +1205,16 @@ export default class GoTrueClient {
|
|
|
1143
1205
|
* @param currentSession The current session. If passed in, it must contain a refresh token.
|
|
1144
1206
|
*/
|
|
1145
1207
|
async refreshSession(currentSession?: { refresh_token: string }): Promise<AuthResponse> {
|
|
1208
|
+
await this.initializePromise
|
|
1209
|
+
|
|
1210
|
+
return await this._acquireLock(-1, async () => {
|
|
1211
|
+
return await this._refreshSession(currentSession)
|
|
1212
|
+
})
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
protected async _refreshSession(currentSession?: {
|
|
1216
|
+
refresh_token: string
|
|
1217
|
+
}): Promise<AuthResponse> {
|
|
1146
1218
|
try {
|
|
1147
1219
|
return await this._useSession(async (result) => {
|
|
1148
1220
|
if (!currentSession) {
|
|
@@ -1200,7 +1272,7 @@ export default class GoTrueClient {
|
|
|
1200
1272
|
|
|
1201
1273
|
if (isPKCEFlow) {
|
|
1202
1274
|
if (!params.code) throw new AuthPKCEGrantCodeExchangeError('No code detected.')
|
|
1203
|
-
const { data, error } = await this.
|
|
1275
|
+
const { data, error } = await this._exchangeCodeForSession(params.code)
|
|
1204
1276
|
if (error) throw error
|
|
1205
1277
|
|
|
1206
1278
|
const url = new URL(window.location.href)
|
|
@@ -1238,7 +1310,7 @@ export default class GoTrueClient {
|
|
|
1238
1310
|
const expiresIn = parseInt(expires_in)
|
|
1239
1311
|
const expires_at = timeNow + expiresIn
|
|
1240
1312
|
|
|
1241
|
-
const { data, error } = await this.
|
|
1313
|
+
const { data, error } = await this._getUser(access_token)
|
|
1242
1314
|
if (error) throw error
|
|
1243
1315
|
|
|
1244
1316
|
const session: Session = {
|
|
@@ -1297,7 +1369,17 @@ export default class GoTrueClient {
|
|
|
1297
1369
|
*
|
|
1298
1370
|
* If using others scope, no `SIGNED_OUT` event is fired!
|
|
1299
1371
|
*/
|
|
1300
|
-
async signOut(
|
|
1372
|
+
async signOut(options: SignOut = { scope: 'global' }): Promise<{ error: AuthError | null }> {
|
|
1373
|
+
await this.initializePromise
|
|
1374
|
+
|
|
1375
|
+
return await this._acquireLock(-1, async () => {
|
|
1376
|
+
return await this._signOut(options)
|
|
1377
|
+
})
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
protected async _signOut(
|
|
1381
|
+
{ scope }: SignOut = { scope: 'global' }
|
|
1382
|
+
): Promise<{ error: AuthError | null }> {
|
|
1301
1383
|
return await this._useSession(async (result) => {
|
|
1302
1384
|
const { data, error: sessionError } = result
|
|
1303
1385
|
if (sessionError) {
|
|
@@ -1346,8 +1428,13 @@ export default class GoTrueClient {
|
|
|
1346
1428
|
this._debug('#onAuthStateChange()', 'registered callback with id', id)
|
|
1347
1429
|
|
|
1348
1430
|
this.stateChangeEmitters.set(id, subscription)
|
|
1431
|
+
;(async () => {
|
|
1432
|
+
await this.initializePromise
|
|
1349
1433
|
|
|
1350
|
-
|
|
1434
|
+
await this._acquireLock(-1, async () => {
|
|
1435
|
+
this._emitInitialSession(id)
|
|
1436
|
+
})
|
|
1437
|
+
})()
|
|
1351
1438
|
|
|
1352
1439
|
return { data: { subscription } }
|
|
1353
1440
|
}
|
|
@@ -1796,38 +1883,51 @@ export default class GoTrueClient {
|
|
|
1796
1883
|
this._debug('#_autoRefreshTokenTick()', 'begin')
|
|
1797
1884
|
|
|
1798
1885
|
try {
|
|
1799
|
-
|
|
1886
|
+
await this._acquireLock(0, async () => {
|
|
1887
|
+
try {
|
|
1888
|
+
const now = Date.now()
|
|
1800
1889
|
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1890
|
+
try {
|
|
1891
|
+
return await this._useSession(async (result) => {
|
|
1892
|
+
const {
|
|
1893
|
+
data: { session },
|
|
1894
|
+
} = result
|
|
1895
|
+
|
|
1896
|
+
if (!session || !session.refresh_token || !session.expires_at) {
|
|
1897
|
+
this._debug('#_autoRefreshTokenTick()', 'no session')
|
|
1898
|
+
return
|
|
1899
|
+
}
|
|
1811
1900
|
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1901
|
+
// session will expire in this many ticks (or has already expired if <= 0)
|
|
1902
|
+
const expiresInTicks = Math.floor(
|
|
1903
|
+
(session.expires_at * 1000 - now) / AUTO_REFRESH_TICK_DURATION
|
|
1904
|
+
)
|
|
1816
1905
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1906
|
+
this._debug(
|
|
1907
|
+
'#_autoRefreshTokenTick()',
|
|
1908
|
+
`access token expires in ${expiresInTicks} ticks, a tick lasts ${AUTO_REFRESH_TICK_DURATION}ms, refresh threshold is ${AUTO_REFRESH_TICK_THRESHOLD} ticks`
|
|
1909
|
+
)
|
|
1821
1910
|
|
|
1822
|
-
|
|
1823
|
-
|
|
1911
|
+
if (expiresInTicks <= AUTO_REFRESH_TICK_THRESHOLD) {
|
|
1912
|
+
await this._callRefreshToken(session.refresh_token)
|
|
1913
|
+
}
|
|
1914
|
+
})
|
|
1915
|
+
} catch (e: any) {
|
|
1916
|
+
console.error(
|
|
1917
|
+
'Auto refresh tick failed with error. This is likely a transient error.',
|
|
1918
|
+
e
|
|
1919
|
+
)
|
|
1824
1920
|
}
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1921
|
+
} finally {
|
|
1922
|
+
this._debug('#_autoRefreshTokenTick()', 'end')
|
|
1923
|
+
}
|
|
1924
|
+
})
|
|
1925
|
+
} catch (e: any) {
|
|
1926
|
+
if (e.isAcquireTimeout) {
|
|
1927
|
+
this._debug('auto refresh token tick lock not available')
|
|
1928
|
+
} else {
|
|
1929
|
+
throw e
|
|
1828
1930
|
}
|
|
1829
|
-
} finally {
|
|
1830
|
-
this._debug('#_autoRefreshTokenTick()', 'end')
|
|
1831
1931
|
}
|
|
1832
1932
|
}
|
|
1833
1933
|
|
|
@@ -2102,7 +2202,7 @@ export default class GoTrueClient {
|
|
|
2102
2202
|
const {
|
|
2103
2203
|
data: { user },
|
|
2104
2204
|
error: userError,
|
|
2105
|
-
} = await this.
|
|
2205
|
+
} = await this._getUser()
|
|
2106
2206
|
if (userError) {
|
|
2107
2207
|
return { data: null, error: userError }
|
|
2108
2208
|
}
|
package/src/lib/helpers.ts
CHANGED
|
@@ -298,143 +298,3 @@ export async function generatePKCEChallenge(verifier: string) {
|
|
|
298
298
|
const hashed = await sha256(verifier)
|
|
299
299
|
return base64urlencode(hashed)
|
|
300
300
|
}
|
|
301
|
-
|
|
302
|
-
const STACK_GUARD_PREFIX = `__stack_guard__`
|
|
303
|
-
const STACK_GUARD_SUFFIX = `__`
|
|
304
|
-
|
|
305
|
-
// Firefox and WebKit based browsers encode the stack entry differently, but
|
|
306
|
-
// they all include the function name. So instead of trying to parse the entry,
|
|
307
|
-
// we're only looking for the special string `__stack_guard__${guardName}__`.
|
|
308
|
-
// Guard names can only be letters with dashes or underscores.
|
|
309
|
-
//
|
|
310
|
-
// Example Firefox stack trace:
|
|
311
|
-
// ```
|
|
312
|
-
// __stack_guard__EXAMPLE__@debugger eval code:1:55
|
|
313
|
-
// @debugger eval code:1:3
|
|
314
|
-
// ```
|
|
315
|
-
//
|
|
316
|
-
// Example WebKit/Chrome stack trace:
|
|
317
|
-
// ```
|
|
318
|
-
// Error
|
|
319
|
-
// at Object.__stack_guard__EXAMPLE__ (<anonymous>:1:55)
|
|
320
|
-
// at <anonymous>:1:13
|
|
321
|
-
// ```
|
|
322
|
-
//
|
|
323
|
-
const STACK_ENTRY_REGEX = /__stack_guard__([a-zA-Z0-9_-]+)__/
|
|
324
|
-
|
|
325
|
-
let STACK_GUARD_CHECKED = false
|
|
326
|
-
let STACK_GUARD_CHECK_FN: () => Promise<void> // eslint-disable-line prefer-const
|
|
327
|
-
|
|
328
|
-
let STACK_GUARDS_SUPPORTED = false
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Checks if the current caller of the function is in a {@link
|
|
332
|
-
* #stackGuard} of the provided `name`. Works by looking through
|
|
333
|
-
* the stack trace of an `Error` object for a special function
|
|
334
|
-
* name (generated by {@link #stackGuard}).
|
|
335
|
-
*
|
|
336
|
-
* @param name The name of the stack guard to check for. Must be `[a-zA-Z0-9_-]` only.
|
|
337
|
-
*/
|
|
338
|
-
export function isInStackGuard(name: string): boolean {
|
|
339
|
-
STACK_GUARD_CHECK_FN()
|
|
340
|
-
|
|
341
|
-
let error: Error
|
|
342
|
-
|
|
343
|
-
try {
|
|
344
|
-
throw new Error()
|
|
345
|
-
} catch (e: any) {
|
|
346
|
-
error = e
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const stack = error.stack?.split('\n') ?? []
|
|
350
|
-
|
|
351
|
-
for (let i = 0; i < stack.length; i += 1) {
|
|
352
|
-
const entry = stack[i]
|
|
353
|
-
const match = entry.match(STACK_ENTRY_REGEX)
|
|
354
|
-
|
|
355
|
-
if (match && match[1] === name) {
|
|
356
|
-
return true
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return false
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Creates a minification resistant stack guard, i.e. if you
|
|
365
|
-
* call {@link #isInStackGuard} from within the `fn` parameter
|
|
366
|
-
* function, you will always get `true` otherwise it will be
|
|
367
|
-
* `false`.
|
|
368
|
-
*
|
|
369
|
-
* Works by dynamically defining a function name before calling
|
|
370
|
-
* into `fn`, which is then parsed from the stack trace on an
|
|
371
|
-
* `Error` object within {@link #isInStackGuard}.
|
|
372
|
-
*
|
|
373
|
-
* @param name The name of the stack guard. Must be `[a-zA-Z0-9_-]` only.
|
|
374
|
-
* @param fn The async/await function to be run within the stack guard.
|
|
375
|
-
*/
|
|
376
|
-
export async function stackGuard<R>(name: string, fn: () => Promise<R>): Promise<R> {
|
|
377
|
-
await STACK_GUARD_CHECK_FN()
|
|
378
|
-
|
|
379
|
-
const guardName = `${STACK_GUARD_PREFIX}${name}${STACK_GUARD_SUFFIX}`
|
|
380
|
-
|
|
381
|
-
const guardFunc: {
|
|
382
|
-
[funcName: string]: () => Promise<R>
|
|
383
|
-
} = {
|
|
384
|
-
// per ECMAScript rules, this defines a new function with the dynamic name
|
|
385
|
-
// contained in the `guardName` variable
|
|
386
|
-
// this function name shows up in stack traces and is resistant to mangling
|
|
387
|
-
// from minification processes as it is determined at runtime
|
|
388
|
-
[guardName]: async () => await fn(),
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Safari does not log the name of a dynamically named function unless you
|
|
392
|
-
// explicitly set the displayName
|
|
393
|
-
Object.assign(guardFunc[guardName], { displayName: guardName })
|
|
394
|
-
|
|
395
|
-
return await guardFunc[guardName]()
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Returns if the JavaScript engine supports stack guards. If it doesn't
|
|
400
|
-
* certain features that depend on detecting recursive calls should be disabled
|
|
401
|
-
* to prevent deadlocks.
|
|
402
|
-
*/
|
|
403
|
-
export async function stackGuardsSupported(): Promise<boolean> {
|
|
404
|
-
if (STACK_GUARD_CHECKED) {
|
|
405
|
-
return STACK_GUARDS_SUPPORTED
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
await STACK_GUARD_CHECK_FN()
|
|
409
|
-
|
|
410
|
-
return STACK_GUARDS_SUPPORTED
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
let STACK_GUARD_WARNING_LOGGED = false
|
|
414
|
-
|
|
415
|
-
// In certain cases, if this file is transpiled using an ES2015 target, or is
|
|
416
|
-
// running in a JS engine that does not support async/await stack traces, this
|
|
417
|
-
// function will log a single warning message.
|
|
418
|
-
STACK_GUARD_CHECK_FN = async () => {
|
|
419
|
-
if (!STACK_GUARD_CHECKED) {
|
|
420
|
-
STACK_GUARD_CHECKED = true
|
|
421
|
-
|
|
422
|
-
await stackGuard('ENV_CHECK', async () => {
|
|
423
|
-
// sleeping for the next tick as Safari loses track of the async/await
|
|
424
|
-
// trace beyond this point
|
|
425
|
-
await sleep(0)
|
|
426
|
-
|
|
427
|
-
const result = isInStackGuard('ENV_CHECK')
|
|
428
|
-
STACK_GUARDS_SUPPORTED = result
|
|
429
|
-
|
|
430
|
-
if (!result && !STACK_GUARD_WARNING_LOGGED) {
|
|
431
|
-
STACK_GUARD_WARNING_LOGGED = true
|
|
432
|
-
console.warn(
|
|
433
|
-
'@supabase/gotrue-js: Stack guards not supported in this environment. Generally not an issue but may point to a very conservative transpilation environment (use ES2017 or above) that implements async/await with generators, or this is a JavaScript engine that does not support async/await stack traces. Safari is known to not support stack guards.'
|
|
434
|
-
)
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return result
|
|
438
|
-
})
|
|
439
|
-
}
|
|
440
|
-
}
|