@depup/supabase__auth-js 2.103.0-depup.0 → 2.110.8-depup.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/AGENTS.md +11 -0
- package/README.md +2 -2
- package/changes.json +1 -1
- package/dist/main/GoTrueAdminApi.d.ts +45 -8
- package/dist/main/GoTrueAdminApi.d.ts.map +1 -1
- package/dist/main/GoTrueAdminApi.js +67 -7
- package/dist/main/GoTrueAdminApi.js.map +1 -1
- package/dist/main/GoTrueClient.d.ts +239 -42
- package/dist/main/GoTrueClient.d.ts.map +1 -1
- package/dist/main/GoTrueClient.js +946 -164
- package/dist/main/GoTrueClient.js.map +1 -1
- package/dist/main/lib/constants.d.ts +8 -0
- package/dist/main/lib/constants.d.ts.map +1 -1
- package/dist/main/lib/constants.js +9 -1
- package/dist/main/lib/constants.js.map +1 -1
- package/dist/main/lib/errors.d.ts +42 -3
- package/dist/main/lib/errors.d.ts.map +1 -1
- package/dist/main/lib/errors.js +44 -13
- package/dist/main/lib/errors.js.map +1 -1
- package/dist/main/lib/fetch.d.ts +28 -8
- package/dist/main/lib/fetch.d.ts.map +1 -1
- package/dist/main/lib/fetch.js +28 -6
- package/dist/main/lib/fetch.js.map +1 -1
- package/dist/main/lib/helpers.d.ts +4 -1
- package/dist/main/lib/helpers.d.ts.map +1 -1
- package/dist/main/lib/helpers.js +15 -4
- package/dist/main/lib/helpers.js.map +1 -1
- package/dist/main/lib/locks.d.ts +29 -35
- package/dist/main/lib/locks.d.ts.map +1 -1
- package/dist/main/lib/locks.js +37 -38
- package/dist/main/lib/locks.js.map +1 -1
- package/dist/main/lib/types.d.ts +305 -64
- package/dist/main/lib/types.d.ts.map +1 -1
- package/dist/main/lib/types.js.map +1 -1
- package/dist/main/lib/version.d.ts +1 -1
- package/dist/main/lib/version.js +1 -1
- package/dist/main/lib/webauthn.d.ts +8 -0
- package/dist/main/lib/webauthn.d.ts.map +1 -1
- package/dist/main/lib/webauthn.dom.d.ts +3 -3
- package/dist/main/lib/webauthn.dom.d.ts.map +1 -1
- package/dist/main/lib/webauthn.errors.d.ts +5 -0
- package/dist/main/lib/webauthn.errors.d.ts.map +1 -1
- package/dist/main/lib/webauthn.errors.js +7 -0
- package/dist/main/lib/webauthn.errors.js.map +1 -1
- package/dist/main/lib/webauthn.js +1 -0
- package/dist/main/lib/webauthn.js.map +1 -1
- package/dist/module/GoTrueAdminApi.d.ts +45 -8
- package/dist/module/GoTrueAdminApi.d.ts.map +1 -1
- package/dist/module/GoTrueAdminApi.js +68 -8
- package/dist/module/GoTrueAdminApi.js.map +1 -1
- package/dist/module/GoTrueClient.d.ts +239 -42
- package/dist/module/GoTrueClient.d.ts.map +1 -1
- package/dist/module/GoTrueClient.js +951 -169
- package/dist/module/GoTrueClient.js.map +1 -1
- package/dist/module/lib/constants.d.ts +8 -0
- package/dist/module/lib/constants.d.ts.map +1 -1
- package/dist/module/lib/constants.js +8 -0
- package/dist/module/lib/constants.js.map +1 -1
- package/dist/module/lib/errors.d.ts +42 -3
- package/dist/module/lib/errors.d.ts.map +1 -1
- package/dist/module/lib/errors.js +41 -12
- package/dist/module/lib/errors.js.map +1 -1
- package/dist/module/lib/fetch.d.ts +28 -8
- package/dist/module/lib/fetch.d.ts.map +1 -1
- package/dist/module/lib/fetch.js +28 -6
- package/dist/module/lib/fetch.js.map +1 -1
- package/dist/module/lib/helpers.d.ts +4 -1
- package/dist/module/lib/helpers.d.ts.map +1 -1
- package/dist/module/lib/helpers.js +14 -4
- package/dist/module/lib/helpers.js.map +1 -1
- package/dist/module/lib/locks.d.ts +29 -35
- package/dist/module/lib/locks.d.ts.map +1 -1
- package/dist/module/lib/locks.js +37 -38
- package/dist/module/lib/locks.js.map +1 -1
- package/dist/module/lib/types.d.ts +305 -64
- package/dist/module/lib/types.d.ts.map +1 -1
- package/dist/module/lib/types.js.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.js +1 -1
- package/dist/module/lib/webauthn.d.ts +8 -0
- package/dist/module/lib/webauthn.d.ts.map +1 -1
- package/dist/module/lib/webauthn.dom.d.ts +3 -3
- package/dist/module/lib/webauthn.dom.d.ts.map +1 -1
- package/dist/module/lib/webauthn.errors.d.ts +5 -0
- package/dist/module/lib/webauthn.errors.d.ts.map +1 -1
- package/dist/module/lib/webauthn.errors.js +7 -0
- package/dist/module/lib/webauthn.errors.js.map +1 -1
- package/dist/module/lib/webauthn.js +1 -1
- package/dist/module/lib/webauthn.js.map +1 -1
- package/dist/tsconfig.module.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/migrations/README.md +25 -0
- package/migrations/lockless-coordination.md +155 -0
- package/package.json +25 -12
- package/src/GoTrueAdminApi.ts +99 -7
- package/src/GoTrueClient.ts +1117 -181
- package/src/lib/constants.ts +9 -0
- package/src/lib/errors.ts +76 -9
- package/src/lib/fetch.ts +66 -24
- package/src/lib/helpers.ts +19 -6
- package/src/lib/locks.ts +44 -42
- package/src/lib/types.ts +374 -82
- package/src/lib/version.ts +1 -1
- package/src/lib/webauthn.dom.ts +3 -3
- package/src/lib/webauthn.errors.ts +12 -0
- package/src/lib/webauthn.ts +1 -1
package/src/lib/constants.ts
CHANGED
|
@@ -12,6 +12,15 @@ export const AUTO_REFRESH_TICK_THRESHOLD = 3
|
|
|
12
12
|
*/
|
|
13
13
|
export const EXPIRY_MARGIN_MS = AUTO_REFRESH_TICK_THRESHOLD * AUTO_REFRESH_TICK_DURATION_MS
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* After a refresh fails, serial callers (including the next auto-refresh
|
|
17
|
+
* tick) within this window receive the cached failure instead of firing
|
|
18
|
+
* another /token request. Two ticks: each outage burns at most one /token
|
|
19
|
+
* call per cooldown window. Cleared on any successful refresh (locally or
|
|
20
|
+
* via BroadcastChannel from another tab) and on `_removeSession`.
|
|
21
|
+
*/
|
|
22
|
+
export const REFRESH_FAILURE_COOLDOWN_MS = 2 * AUTO_REFRESH_TICK_DURATION_MS
|
|
23
|
+
|
|
15
24
|
export const GOTRUE_URL = 'http://localhost:9999'
|
|
16
25
|
export const STORAGE_KEY = 'supabase.auth.token'
|
|
17
26
|
export const AUDIENCE = ''
|
package/src/lib/errors.ts
CHANGED
|
@@ -16,7 +16,7 @@ export class AuthError extends Error {
|
|
|
16
16
|
* Error code associated with the error. Most errors coming from
|
|
17
17
|
* HTTP responses will have a code, though some errors that occur
|
|
18
18
|
* before a response is received will not have one present. In that
|
|
19
|
-
* case {@link
|
|
19
|
+
* case {@link AuthError.status} will also be undefined.
|
|
20
20
|
*/
|
|
21
21
|
code: ErrorCode | (string & {}) | undefined
|
|
22
22
|
|
|
@@ -31,6 +31,20 @@ export class AuthError extends Error {
|
|
|
31
31
|
this.status = status
|
|
32
32
|
this.code = code
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
toJSON(): {
|
|
36
|
+
name: string
|
|
37
|
+
message: string
|
|
38
|
+
status: number | undefined
|
|
39
|
+
code: ErrorCode | (string & {}) | undefined
|
|
40
|
+
} {
|
|
41
|
+
return {
|
|
42
|
+
name: this.name,
|
|
43
|
+
message: this.message,
|
|
44
|
+
status: this.status,
|
|
45
|
+
code: this.code,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
34
48
|
}
|
|
35
49
|
|
|
36
50
|
export function isAuthError(error: unknown): error is AuthError {
|
|
@@ -179,11 +193,15 @@ export class AuthImplicitGrantRedirectError extends CustomAuthError {
|
|
|
179
193
|
this.details = details
|
|
180
194
|
}
|
|
181
195
|
|
|
182
|
-
toJSON() {
|
|
196
|
+
toJSON(): {
|
|
197
|
+
name: string
|
|
198
|
+
message: string
|
|
199
|
+
status: number | undefined
|
|
200
|
+
code: ErrorCode | (string & {}) | undefined
|
|
201
|
+
details: { error: string; code: string } | null
|
|
202
|
+
} {
|
|
183
203
|
return {
|
|
184
|
-
|
|
185
|
-
message: this.message,
|
|
186
|
-
status: this.status,
|
|
204
|
+
...super.toJSON(),
|
|
187
205
|
details: this.details,
|
|
188
206
|
}
|
|
189
207
|
}
|
|
@@ -213,11 +231,15 @@ export class AuthPKCEGrantCodeExchangeError extends CustomAuthError {
|
|
|
213
231
|
this.details = details
|
|
214
232
|
}
|
|
215
233
|
|
|
216
|
-
toJSON() {
|
|
234
|
+
toJSON(): {
|
|
235
|
+
name: string
|
|
236
|
+
message: string
|
|
237
|
+
status: number | undefined
|
|
238
|
+
code: ErrorCode | (string & {}) | undefined
|
|
239
|
+
details: { error: string; code: string } | null
|
|
240
|
+
} {
|
|
217
241
|
return {
|
|
218
|
-
|
|
219
|
-
message: this.message,
|
|
220
|
-
status: this.status,
|
|
242
|
+
...super.toJSON(),
|
|
221
243
|
details: this.details,
|
|
222
244
|
}
|
|
223
245
|
}
|
|
@@ -275,6 +297,38 @@ export function isAuthRetryableFetchError(error: unknown): error is AuthRetryabl
|
|
|
275
297
|
return isAuthError(error) && error.name === 'AuthRetryableFetchError'
|
|
276
298
|
}
|
|
277
299
|
|
|
300
|
+
/**
|
|
301
|
+
* Returned when the server rotated a refresh token successfully but the
|
|
302
|
+
* client chose not to persist the rotated tokens because the local session
|
|
303
|
+
* changed mid-flight. Usually means a concurrent `signOut` cleared storage
|
|
304
|
+
* between when the refresh started and when it came back.
|
|
305
|
+
*
|
|
306
|
+
* Set on the `error` field of the refresh result so callers can tell "we
|
|
307
|
+
* got rotated tokens but threw them away" apart from "the refresh failed."
|
|
308
|
+
* The rotated session on the server will be picked up on the next refresh
|
|
309
|
+
* via GoTrue's parent-of-active path.
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```ts
|
|
313
|
+
* import { isAuthRefreshDiscardedError } from '@supabase/auth-js'
|
|
314
|
+
*
|
|
315
|
+
* if (isAuthRefreshDiscardedError(error)) {
|
|
316
|
+
* // Concurrent signOut/sign-in raced our refresh. Treat as a no-op.
|
|
317
|
+
* }
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
export class AuthRefreshDiscardedError extends CustomAuthError {
|
|
321
|
+
constructor(
|
|
322
|
+
message = 'Refresh result discarded: session state changed mid-flight (e.g., concurrent signOut)'
|
|
323
|
+
) {
|
|
324
|
+
super(message, 'AuthRefreshDiscardedError', 409, undefined)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export function isAuthRefreshDiscardedError(error: unknown): error is AuthRefreshDiscardedError {
|
|
329
|
+
return isAuthError(error) && error.name === 'AuthRefreshDiscardedError'
|
|
330
|
+
}
|
|
331
|
+
|
|
278
332
|
/**
|
|
279
333
|
* This error is thrown on certain methods when the password used is deemed
|
|
280
334
|
* weak. Inspect the reasons to identify what password strength rules are
|
|
@@ -301,6 +355,19 @@ export class AuthWeakPasswordError extends CustomAuthError {
|
|
|
301
355
|
|
|
302
356
|
this.reasons = reasons
|
|
303
357
|
}
|
|
358
|
+
|
|
359
|
+
toJSON(): {
|
|
360
|
+
name: string
|
|
361
|
+
message: string
|
|
362
|
+
status: number | undefined
|
|
363
|
+
code: ErrorCode | (string & {}) | undefined
|
|
364
|
+
reasons: WeakPasswordReasons[]
|
|
365
|
+
} {
|
|
366
|
+
return {
|
|
367
|
+
...super.toJSON(),
|
|
368
|
+
reasons: this.reasons,
|
|
369
|
+
}
|
|
370
|
+
}
|
|
304
371
|
}
|
|
305
372
|
|
|
306
373
|
export function isAuthWeakPasswordError(error: unknown): error is AuthWeakPasswordError {
|
package/src/lib/fetch.ts
CHANGED
|
@@ -3,11 +3,13 @@ import { expiresAt, looksLikeFetchResponse, parseResponseAPIVersion } from './he
|
|
|
3
3
|
import {
|
|
4
4
|
AuthResponse,
|
|
5
5
|
AuthResponsePassword,
|
|
6
|
+
Session,
|
|
6
7
|
SSOResponse,
|
|
7
8
|
GenerateLinkProperties,
|
|
8
9
|
GenerateLinkResponse,
|
|
9
10
|
User,
|
|
10
11
|
UserResponse,
|
|
12
|
+
WeakPassword,
|
|
11
13
|
} from './types'
|
|
12
14
|
import {
|
|
13
15
|
AuthApiError,
|
|
@@ -19,6 +21,30 @@ import {
|
|
|
19
21
|
|
|
20
22
|
export type Fetch = typeof fetch
|
|
21
23
|
|
|
24
|
+
/** Raw session data from GoTrue server response. */
|
|
25
|
+
interface GoTrueSessionData {
|
|
26
|
+
access_token?: string
|
|
27
|
+
refresh_token?: string
|
|
28
|
+
expires_in?: number
|
|
29
|
+
expires_at?: number
|
|
30
|
+
user?: User
|
|
31
|
+
[key: string]: any // server returns additional fields (token_type, provider_token, etc.) copied into Session
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Raw session data that includes weak password info (password sign-in endpoints). */
|
|
35
|
+
interface GoTrueSessionPasswordData extends GoTrueSessionData {
|
|
36
|
+
weak_password?: WeakPassword
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Raw user data — either `{ user: User }` or the User object itself. */
|
|
40
|
+
interface GoTrueUserData {
|
|
41
|
+
user?: User
|
|
42
|
+
[key: string]: any // data may BE the User directly (fallback path)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Raw generate-link data — link properties + User fields flattened into one object. */
|
|
46
|
+
type GoTrueGenerateLinkData = GenerateLinkProperties & Record<string, any>
|
|
47
|
+
|
|
22
48
|
export interface FetchOptions {
|
|
23
49
|
headers?: {
|
|
24
50
|
[key: string]: string
|
|
@@ -30,12 +56,25 @@ export interface FetchParameters {
|
|
|
30
56
|
signal?: AbortSignal
|
|
31
57
|
}
|
|
32
58
|
|
|
33
|
-
export type RequestMethodType = 'GET' | 'POST' | 'PUT' | 'DELETE'
|
|
59
|
+
export type RequestMethodType = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
|
34
60
|
|
|
35
|
-
const _getErrorMessage = (err:
|
|
36
|
-
|
|
61
|
+
const _getErrorMessage = (err: unknown): string => {
|
|
62
|
+
if (typeof err === 'object' && err !== null) {
|
|
63
|
+
const e = err as Record<string, unknown>
|
|
64
|
+
if (typeof e.msg === 'string') return e.msg
|
|
65
|
+
if (typeof e.message === 'string') return e.message
|
|
66
|
+
if (typeof e.error_description === 'string') return e.error_description
|
|
67
|
+
if (typeof e.error === 'string') return e.error
|
|
68
|
+
}
|
|
69
|
+
return JSON.stringify(err)
|
|
70
|
+
}
|
|
37
71
|
|
|
38
|
-
|
|
72
|
+
// 500, 501, 502, 503, 504: Standard server/gateway errors
|
|
73
|
+
// 520-529, 530: Cloudflare-specific error codes (web server down, connection timed out, etc.)
|
|
74
|
+
// These are infrastructure errors and should not cause session invalidation.
|
|
75
|
+
const NETWORK_ERROR_CODES = [
|
|
76
|
+
500, 501, 502, 503, 504, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530,
|
|
77
|
+
]
|
|
39
78
|
|
|
40
79
|
export async function handleError(error: unknown) {
|
|
41
80
|
if (!looksLikeFetchResponse(error)) {
|
|
@@ -50,7 +89,7 @@ export async function handleError(error: unknown) {
|
|
|
50
89
|
let data: any
|
|
51
90
|
try {
|
|
52
91
|
data = await error.json()
|
|
53
|
-
} catch (e
|
|
92
|
+
} catch (e) {
|
|
54
93
|
throw new AuthUnknownError(_getErrorMessage(e), e)
|
|
55
94
|
}
|
|
56
95
|
|
|
@@ -178,16 +217,17 @@ async function _handleRequest(
|
|
|
178
217
|
): Promise<any> {
|
|
179
218
|
const requestParams = _getRequestParams(method, options, parameters, body)
|
|
180
219
|
|
|
181
|
-
let result:
|
|
220
|
+
let result: Response
|
|
182
221
|
|
|
183
222
|
try {
|
|
184
223
|
result = await fetcher(url, {
|
|
185
224
|
...requestParams,
|
|
186
225
|
})
|
|
187
226
|
} catch (e) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
//
|
|
227
|
+
// fetch failed (network / CORS / aborted request) — surfaced to the
|
|
228
|
+
// caller as a retryable error below. Deliberately not logged here: an
|
|
229
|
+
// aborted in-flight request (e.g. a superseded page navigation) is a
|
|
230
|
+
// transient condition, and logging the raw error pollutes the console.
|
|
191
231
|
throw new AuthRetryableFetchError(_getErrorMessage(e), 0)
|
|
192
232
|
}
|
|
193
233
|
|
|
@@ -201,26 +241,28 @@ async function _handleRequest(
|
|
|
201
241
|
|
|
202
242
|
try {
|
|
203
243
|
return await result.json()
|
|
204
|
-
} catch (e
|
|
244
|
+
} catch (e) {
|
|
205
245
|
await handleError(e)
|
|
206
246
|
}
|
|
207
247
|
}
|
|
208
248
|
|
|
209
|
-
export function _sessionResponse(data:
|
|
249
|
+
export function _sessionResponse(data: GoTrueSessionData): AuthResponse {
|
|
210
250
|
let session = null
|
|
211
251
|
if (hasSession(data)) {
|
|
212
|
-
session = { ...data }
|
|
252
|
+
session = { ...data } as Session
|
|
213
253
|
|
|
214
254
|
if (!data.expires_at) {
|
|
215
|
-
session.expires_at = expiresAt(data.expires_in)
|
|
255
|
+
session.expires_at = expiresAt(data.expires_in!)
|
|
216
256
|
}
|
|
217
257
|
}
|
|
218
258
|
|
|
219
|
-
|
|
259
|
+
// Some /verify responses (e.g. secure email_change first-confirmation) return
|
|
260
|
+
// only `{ msg, code }` with no user and no session. Treat those as null user.
|
|
261
|
+
const user: User | null = data.user ?? (typeof data?.id === 'string' ? (data as User) : null)
|
|
220
262
|
return { data: { session, user }, error: null }
|
|
221
263
|
}
|
|
222
264
|
|
|
223
|
-
export function _sessionResponsePassword(data:
|
|
265
|
+
export function _sessionResponsePassword(data: GoTrueSessionPasswordData): AuthResponsePassword {
|
|
224
266
|
const response = _sessionResponse(data) as AuthResponsePassword
|
|
225
267
|
|
|
226
268
|
if (
|
|
@@ -231,7 +273,7 @@ export function _sessionResponsePassword(data: any): AuthResponsePassword {
|
|
|
231
273
|
data.weak_password.reasons.length &&
|
|
232
274
|
data.weak_password.message &&
|
|
233
275
|
typeof data.weak_password.message === 'string' &&
|
|
234
|
-
data.weak_password.reasons.reduce((a: boolean, i:
|
|
276
|
+
data.weak_password.reasons.reduce((a: boolean, i: unknown) => a && typeof i === 'string', true)
|
|
235
277
|
) {
|
|
236
278
|
response.data.weak_password = data.weak_password
|
|
237
279
|
}
|
|
@@ -239,16 +281,16 @@ export function _sessionResponsePassword(data: any): AuthResponsePassword {
|
|
|
239
281
|
return response
|
|
240
282
|
}
|
|
241
283
|
|
|
242
|
-
export function _userResponse(data:
|
|
284
|
+
export function _userResponse(data: GoTrueUserData): UserResponse {
|
|
243
285
|
const user: User = data.user ?? (data as User)
|
|
244
286
|
return { data: { user }, error: null }
|
|
245
287
|
}
|
|
246
288
|
|
|
247
|
-
export function _ssoResponse(data: any): SSOResponse {
|
|
248
|
-
return { data, error: null }
|
|
289
|
+
export function _ssoResponse(data: Record<string, any>): SSOResponse {
|
|
290
|
+
return { data, error: null } as SSOResponse
|
|
249
291
|
}
|
|
250
292
|
|
|
251
|
-
export function _generateLinkResponse(data:
|
|
293
|
+
export function _generateLinkResponse(data: GoTrueGenerateLinkData): GenerateLinkResponse {
|
|
252
294
|
const { action_link, email_otp, hashed_token, redirect_to, verification_type, ...rest } = data
|
|
253
295
|
|
|
254
296
|
const properties: GenerateLinkProperties = {
|
|
@@ -259,7 +301,7 @@ export function _generateLinkResponse(data: any): GenerateLinkResponse {
|
|
|
259
301
|
verification_type,
|
|
260
302
|
}
|
|
261
303
|
|
|
262
|
-
const user
|
|
304
|
+
const user = { ...rest } as User
|
|
263
305
|
return {
|
|
264
306
|
data: {
|
|
265
307
|
properties,
|
|
@@ -269,7 +311,7 @@ export function _generateLinkResponse(data: any): GenerateLinkResponse {
|
|
|
269
311
|
}
|
|
270
312
|
}
|
|
271
313
|
|
|
272
|
-
export function _noResolveJsonResponse(data:
|
|
314
|
+
export function _noResolveJsonResponse(data: Response): Response {
|
|
273
315
|
return data
|
|
274
316
|
}
|
|
275
317
|
|
|
@@ -278,6 +320,6 @@ export function _noResolveJsonResponse(data: any): Response {
|
|
|
278
320
|
* @param data A response object
|
|
279
321
|
* @returns true if a session is in the response
|
|
280
322
|
*/
|
|
281
|
-
function hasSession(data:
|
|
282
|
-
return data.access_token && data.refresh_token && data.expires_in
|
|
323
|
+
function hasSession(data: GoTrueSessionData): boolean {
|
|
324
|
+
return !!data.access_token && !!data.refresh_token && !!data.expires_in
|
|
283
325
|
}
|
package/src/lib/helpers.ts
CHANGED
|
@@ -87,7 +87,7 @@ export function parseParametersFromURL(href: string) {
|
|
|
87
87
|
hashSearchParams.forEach((value, key) => {
|
|
88
88
|
result[key] = value
|
|
89
89
|
})
|
|
90
|
-
} catch (
|
|
90
|
+
} catch (_e) {
|
|
91
91
|
// hash is not a query string
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -139,7 +139,12 @@ export const getItemAsync = async (storage: SupportedStorage, key: string): Prom
|
|
|
139
139
|
try {
|
|
140
140
|
return JSON.parse(value)
|
|
141
141
|
} catch {
|
|
142
|
-
|
|
142
|
+
// Storage values are always written as JSON via setItemAsync. A non-JSON
|
|
143
|
+
// value means the entry is corrupted (e.g. mismatched chunked cookies in
|
|
144
|
+
// SSR contexts). Treat as absent so callers do not mutate or re-save the
|
|
145
|
+
// garbage, which would otherwise trigger a TypeError downstream and
|
|
146
|
+
// leak the raw value into error logs.
|
|
147
|
+
return null
|
|
143
148
|
}
|
|
144
149
|
}
|
|
145
150
|
|
|
@@ -235,7 +240,7 @@ export function retryable<T>(
|
|
|
235
240
|
accept(result)
|
|
236
241
|
return
|
|
237
242
|
}
|
|
238
|
-
} catch (e
|
|
243
|
+
} catch (e) {
|
|
239
244
|
if (!isRetryable(attempt, e)) {
|
|
240
245
|
reject(e)
|
|
241
246
|
return
|
|
@@ -304,7 +309,7 @@ export async function getCodeChallengeAndMethod(
|
|
|
304
309
|
const codeVerifier = generatePKCEVerifier()
|
|
305
310
|
let storedCodeVerifier = codeVerifier
|
|
306
311
|
if (isPasswordRecovery) {
|
|
307
|
-
storedCodeVerifier += '/
|
|
312
|
+
storedCodeVerifier += '/recovery'
|
|
308
313
|
}
|
|
309
314
|
await setItemAsync(storage, `${storageKey}-code-verifier`, storedCodeVerifier)
|
|
310
315
|
const codeChallenge = await generatePKCEChallenge(codeVerifier)
|
|
@@ -329,7 +334,7 @@ export function parseResponseAPIVersion(response: Response) {
|
|
|
329
334
|
try {
|
|
330
335
|
const date = new Date(`${apiVersion}T00:00:00.0Z`)
|
|
331
336
|
return date
|
|
332
|
-
} catch (
|
|
337
|
+
} catch (_e) {
|
|
333
338
|
return null
|
|
334
339
|
}
|
|
335
340
|
}
|
|
@@ -345,7 +350,7 @@ export function validateExp(exp: number) {
|
|
|
345
350
|
}
|
|
346
351
|
|
|
347
352
|
export function getAlgorithm(
|
|
348
|
-
alg: 'HS256' | 'RS256' | 'ES256'
|
|
353
|
+
alg: 'HS256' | 'RS256' | 'ES256' | (string & {})
|
|
349
354
|
): RsaHashedImportParams | EcKeyImportParams {
|
|
350
355
|
switch (alg) {
|
|
351
356
|
case 'RS256':
|
|
@@ -372,6 +377,14 @@ export function validateUUID(str: string) {
|
|
|
372
377
|
}
|
|
373
378
|
}
|
|
374
379
|
|
|
380
|
+
export function assertPasskeyExperimentalEnabled(experimental: { passkey?: boolean }): void {
|
|
381
|
+
if (!experimental.passkey) {
|
|
382
|
+
throw new Error(
|
|
383
|
+
'@supabase/auth-js: the passkey API is experimental and disabled by default. Enable it by passing `auth: { experimental: { passkey: true } }` to createClient (or to the GoTrueClient constructor).'
|
|
384
|
+
)
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
375
388
|
export function userNotAvailableProxy(): User {
|
|
376
389
|
const proxyTarget = {} as User
|
|
377
390
|
|
package/src/lib/locks.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lock primitives retained for backwards-compatible imports. The auth client
|
|
3
|
+
* coordinates refreshes itself (deduping in-instance callers onto a shared
|
|
4
|
+
* in-flight promise) and lets the GoTrue server resolve cross-instance races,
|
|
5
|
+
* so it does not invoke any primitive from this module. The functions still
|
|
6
|
+
* work for direct callers that need a navigator.locks-backed or in-process
|
|
7
|
+
* exclusive lock of their own.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
import { supportsLocalStorage } from './helpers'
|
|
2
11
|
|
|
3
12
|
/**
|
|
13
|
+
* @deprecated Debug flag for `navigatorLock` / `processLock`. The auth
|
|
14
|
+
* client ignores both, so this has no client-side effect.
|
|
4
15
|
* @experimental
|
|
5
16
|
*/
|
|
6
17
|
export const internals = {
|
|
@@ -18,18 +29,9 @@ export const internals = {
|
|
|
18
29
|
/**
|
|
19
30
|
* An error thrown when a lock cannot be acquired after some amount of time.
|
|
20
31
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* ```ts
|
|
25
|
-
* import { LockAcquireTimeoutError } from '@supabase/auth-js'
|
|
26
|
-
*
|
|
27
|
-
* class CustomLockError extends LockAcquireTimeoutError {
|
|
28
|
-
* constructor() {
|
|
29
|
-
* super('Lock timed out')
|
|
30
|
-
* }
|
|
31
|
-
* }
|
|
32
|
-
* ```
|
|
32
|
+
* @deprecated The auth client doesn't acquire locks around auth operations,
|
|
33
|
+
* so this error never originates from `supabase.auth.*` calls. Direct callers
|
|
34
|
+
* of `navigatorLock` / `processLock` still receive it on acquire timeout.
|
|
33
35
|
*/
|
|
34
36
|
export abstract class LockAcquireTimeoutError extends Error {
|
|
35
37
|
public readonly isAcquireTimeout = true
|
|
@@ -40,25 +42,15 @@ export abstract class LockAcquireTimeoutError extends Error {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* ```ts
|
|
47
|
-
* import { NavigatorLockAcquireTimeoutError } from '@supabase/auth-js'
|
|
48
|
-
*
|
|
49
|
-
* throw new NavigatorLockAcquireTimeoutError('Lock timed out')
|
|
50
|
-
* ```
|
|
45
|
+
* @deprecated The auth client doesn't call `navigator.locks`, so this error
|
|
46
|
+
* never originates from `supabase.auth.*` calls. Direct callers of
|
|
47
|
+
* `navigatorLock` still receive it on acquire timeout.
|
|
51
48
|
*/
|
|
52
49
|
export class NavigatorLockAcquireTimeoutError extends LockAcquireTimeoutError {}
|
|
53
50
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* ```ts
|
|
58
|
-
* import { ProcessLockAcquireTimeoutError } from '@supabase/auth-js'
|
|
59
|
-
*
|
|
60
|
-
* throw new ProcessLockAcquireTimeoutError('Lock timed out')
|
|
61
|
-
* ```
|
|
51
|
+
* @deprecated The auth client doesn't run `processLock`, so this error
|
|
52
|
+
* never originates from `supabase.auth.*` calls. Direct callers of
|
|
53
|
+
* `processLock` still receive it on acquire timeout.
|
|
62
54
|
*/
|
|
63
55
|
export class ProcessLockAcquireTimeoutError extends LockAcquireTimeoutError {}
|
|
64
56
|
|
|
@@ -86,12 +78,10 @@ export class ProcessLockAcquireTimeoutError extends LockAcquireTimeoutError {}
|
|
|
86
78
|
* will time out after so many milliseconds. An error is
|
|
87
79
|
* a timeout if it has `isAcquireTimeout` set to true.
|
|
88
80
|
* @param fn The operation to run once the lock is acquired.
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* })
|
|
94
|
-
* ```
|
|
81
|
+
*
|
|
82
|
+
* @deprecated The auth client coordinates refreshes itself and the server
|
|
83
|
+
* resolves concurrent refresh races, so passing `{ lock: navigatorLock }`
|
|
84
|
+
* to it has no effect. You can safely drop the import from your client setup.
|
|
95
85
|
*/
|
|
96
86
|
export async function navigatorLock<R>(
|
|
97
87
|
name: string,
|
|
@@ -176,7 +166,7 @@ export async function navigatorLock<R>(
|
|
|
176
166
|
'@supabase/gotrue-js: Navigator LockManager state',
|
|
177
167
|
JSON.stringify(result, null, ' ')
|
|
178
168
|
)
|
|
179
|
-
} catch (e
|
|
169
|
+
} catch (e) {
|
|
180
170
|
console.warn(
|
|
181
171
|
'@supabase/gotrue-js: Error when querying Navigator LockManager state',
|
|
182
172
|
e
|
|
@@ -198,14 +188,21 @@ export async function navigatorLock<R>(
|
|
|
198
188
|
}
|
|
199
189
|
}
|
|
200
190
|
)
|
|
201
|
-
} catch (e
|
|
191
|
+
} catch (e) {
|
|
202
192
|
// Always clear the acquire timeout once the request settles, so it cannot
|
|
203
193
|
// fire later and incorrectly abort/log after a rejection.
|
|
204
194
|
if (acquireTimeout > 0) {
|
|
205
195
|
clearTimeout(acquireTimeoutTimer)
|
|
206
196
|
}
|
|
207
197
|
|
|
208
|
-
|
|
198
|
+
// DOMException does not extend Error in Node.js, so use structural check
|
|
199
|
+
if (
|
|
200
|
+
e !== null &&
|
|
201
|
+
typeof e === 'object' &&
|
|
202
|
+
'name' in e &&
|
|
203
|
+
e.name === 'AbortError' &&
|
|
204
|
+
acquireTimeout > 0
|
|
205
|
+
) {
|
|
209
206
|
if (abortController.signal.aborted) {
|
|
210
207
|
// OUR timeout fired — the lock is genuinely orphaned. Steal it.
|
|
211
208
|
//
|
|
@@ -305,7 +302,7 @@ const PROCESS_LOCKS: { [name: string]: Promise<any> } = {}
|
|
|
305
302
|
* Useful for environments like React Native or other non-browser
|
|
306
303
|
* single-process (i.e. no concept of "tabs") environments.
|
|
307
304
|
*
|
|
308
|
-
* Use {@link
|
|
305
|
+
* Use {@link navigatorLock} in browser environments.
|
|
309
306
|
*
|
|
310
307
|
* @param name Name of the lock to be acquired.
|
|
311
308
|
* @param acquireTimeout If negative, no timeout. If 0 an error is thrown if
|
|
@@ -313,6 +310,11 @@ const PROCESS_LOCKS: { [name: string]: Promise<any> } = {}
|
|
|
313
310
|
* will time out after so many milliseconds. An error is
|
|
314
311
|
* a timeout if it has `isAcquireTimeout` set to true.
|
|
315
312
|
* @param fn The operation to run once the lock is acquired.
|
|
313
|
+
*
|
|
314
|
+
* @deprecated The auth client coordinates refreshes itself and the server
|
|
315
|
+
* resolves concurrent refresh races, so passing `{ lock: processLock }`
|
|
316
|
+
* to it has no effect. You can safely drop the import from your client setup.
|
|
317
|
+
*
|
|
316
318
|
* @example
|
|
317
319
|
* ```ts
|
|
318
320
|
* await processLock('migrate', 5000, async () => {
|
|
@@ -370,14 +372,14 @@ export async function processLock<R>(
|
|
|
370
372
|
if (timeoutId !== null) {
|
|
371
373
|
clearTimeout(timeoutId)
|
|
372
374
|
}
|
|
373
|
-
} catch (e
|
|
375
|
+
} catch (e) {
|
|
374
376
|
// Clear the timeout on error path as well
|
|
375
377
|
if (timeoutId !== null) {
|
|
376
378
|
clearTimeout(timeoutId)
|
|
377
379
|
}
|
|
378
380
|
|
|
379
381
|
// Re-throw timeout errors, ignore others
|
|
380
|
-
if (e
|
|
382
|
+
if (e instanceof LockAcquireTimeoutError) {
|
|
381
383
|
throw e
|
|
382
384
|
}
|
|
383
385
|
// Fall through to run fn() - previous operation finished with error
|
|
@@ -391,8 +393,8 @@ export async function processLock<R>(
|
|
|
391
393
|
PROCESS_LOCKS[name] = (async () => {
|
|
392
394
|
try {
|
|
393
395
|
return await currentOperation
|
|
394
|
-
} catch (e
|
|
395
|
-
if (e
|
|
396
|
+
} catch (e) {
|
|
397
|
+
if (e instanceof LockAcquireTimeoutError) {
|
|
396
398
|
// if the current operation timed out, it doesn't mean that the previous
|
|
397
399
|
// operation finished, so we need continue waiting for it to finish
|
|
398
400
|
try {
|