@supabase/gotrue-js 2.100.0-rc.0 → 2.100.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.
Files changed (44) hide show
  1. package/dist/main/GoTrueAdminApi.d.ts +449 -0
  2. package/dist/main/GoTrueAdminApi.d.ts.map +1 -1
  3. package/dist/main/GoTrueAdminApi.js +449 -0
  4. package/dist/main/GoTrueAdminApi.js.map +1 -1
  5. package/dist/main/GoTrueClient.d.ts +1668 -63
  6. package/dist/main/GoTrueClient.d.ts.map +1 -1
  7. package/dist/main/GoTrueClient.js +1889 -70
  8. package/dist/main/GoTrueClient.js.map +1 -1
  9. package/dist/main/lib/locks.d.ts.map +1 -1
  10. package/dist/main/lib/locks.js +69 -39
  11. package/dist/main/lib/locks.js.map +1 -1
  12. package/dist/main/lib/types.d.ts +409 -0
  13. package/dist/main/lib/types.d.ts.map +1 -1
  14. package/dist/main/lib/types.js.map +1 -1
  15. package/dist/main/lib/version.d.ts +1 -1
  16. package/dist/main/lib/version.d.ts.map +1 -1
  17. package/dist/main/lib/version.js +1 -1
  18. package/dist/main/lib/version.js.map +1 -1
  19. package/dist/module/GoTrueAdminApi.d.ts +449 -0
  20. package/dist/module/GoTrueAdminApi.d.ts.map +1 -1
  21. package/dist/module/GoTrueAdminApi.js +449 -0
  22. package/dist/module/GoTrueAdminApi.js.map +1 -1
  23. package/dist/module/GoTrueClient.d.ts +1668 -63
  24. package/dist/module/GoTrueClient.d.ts.map +1 -1
  25. package/dist/module/GoTrueClient.js +1889 -70
  26. package/dist/module/GoTrueClient.js.map +1 -1
  27. package/dist/module/lib/locks.d.ts.map +1 -1
  28. package/dist/module/lib/locks.js +69 -39
  29. package/dist/module/lib/locks.js.map +1 -1
  30. package/dist/module/lib/types.d.ts +409 -0
  31. package/dist/module/lib/types.d.ts.map +1 -1
  32. package/dist/module/lib/types.js.map +1 -1
  33. package/dist/module/lib/version.d.ts +1 -1
  34. package/dist/module/lib/version.d.ts.map +1 -1
  35. package/dist/module/lib/version.js +1 -1
  36. package/dist/module/lib/version.js.map +1 -1
  37. package/dist/tsconfig.module.tsbuildinfo +1 -1
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +1 -1
  40. package/src/GoTrueAdminApi.ts +449 -0
  41. package/src/GoTrueClient.ts +1889 -70
  42. package/src/lib/locks.ts +92 -54
  43. package/src/lib/types.ts +409 -0
  44. package/src/lib/version.ts +1 -1
package/src/lib/locks.ts CHANGED
@@ -104,8 +104,10 @@ export async function navigatorLock<R>(
104
104
 
105
105
  const abortController = new globalThis.AbortController()
106
106
 
107
+ let acquireTimeoutTimer: ReturnType<typeof setTimeout> | undefined
108
+
107
109
  if (acquireTimeout > 0) {
108
- setTimeout(() => {
110
+ acquireTimeoutTimer = setTimeout(() => {
109
111
  abortController.abort()
110
112
  if (internals.debug) {
111
113
  console.log('@supabase/gotrue-js: navigatorLock acquire timed out', name)
@@ -138,6 +140,13 @@ export async function navigatorLock<R>(
138
140
  },
139
141
  async (lock) => {
140
142
  if (lock) {
143
+ // Lock acquired — cancel the acquire-timeout timer so it cannot fire
144
+ // while fn() is running. Without this, a delayed timeout abort would
145
+ // set signal.aborted = true even though we already hold the lock,
146
+ // causing a subsequent steal to be misclassified as "our timeout
147
+ // fired" and triggering a spurious steal-back cascade.
148
+ clearTimeout(acquireTimeoutTimer)
149
+
141
150
  if (internals.debug) {
142
151
  console.log('@supabase/gotrue-js: navigatorLock: acquired', name, lock.name)
143
152
  }
@@ -183,77 +192,106 @@ export async function navigatorLock<R>(
183
192
  '@supabase/gotrue-js: Navigator LockManager returned a null lock when using #request without ifAvailable set to true, it appears this browser is not following the LockManager spec https://developer.mozilla.org/en-US/docs/Web/API/LockManager/request'
184
193
  )
185
194
 
195
+ clearTimeout(acquireTimeoutTimer)
186
196
  return await fn()
187
197
  }
188
198
  }
189
199
  }
190
200
  )
191
201
  } catch (e: any) {
192
- if (e?.name === 'AbortError' && acquireTimeout > 0) {
193
- // The lock acquisition was aborted because the timeout fired while the
194
- // request was still pending. This typically means another lock holder is
195
- // not releasing the lock, possibly due to React Strict Mode's
196
- // double-mount/unmount behavior or a component unmounting mid-operation,
197
- // leaving an orphaned lock.
198
- //
199
- // Recovery: use { steal: true } to forcefully acquire the lock. Per the
200
- // Web Locks API spec, this releases any currently held lock with the same
201
- // name and grants the request immediately, preempting any queued requests.
202
- // The previous holder's callback continues running to completion but no
203
- // longer holds the lock for exclusion purposes.
204
- //
205
- // See: https://github.com/supabase/supabase/issues/42505
206
- if (internals.debug) {
207
- console.log(
208
- '@supabase/gotrue-js: navigatorLock: acquire timeout, recovering by stealing lock',
209
- name
210
- )
211
- }
202
+ // Always clear the acquire timeout once the request settles, so it cannot
203
+ // fire later and incorrectly abort/log after a rejection.
204
+ if (acquireTimeout > 0) {
205
+ clearTimeout(acquireTimeoutTimer)
206
+ }
212
207
 
213
- console.warn(
214
- `@supabase/gotrue-js: Lock "${name}" was not released within ${acquireTimeout}ms. ` +
215
- 'This may indicate an orphaned lock from a component unmount (e.g., React Strict Mode). ' +
216
- 'Forcefully acquiring the lock to recover.'
217
- )
208
+ if (e?.name === 'AbortError' && acquireTimeout > 0) {
209
+ if (abortController.signal.aborted) {
210
+ // OUR timeout fired the lock is genuinely orphaned. Steal it.
211
+ //
212
+ // The lock acquisition was aborted because the timeout fired while the
213
+ // request was still pending. This typically means another lock holder is
214
+ // not releasing the lock, possibly due to React Strict Mode's
215
+ // double-mount/unmount behavior or a component unmounting mid-operation,
216
+ // leaving an orphaned lock.
217
+ //
218
+ // Recovery: use { steal: true } to forcefully acquire the lock. Per the
219
+ // Web Locks API spec, this releases any currently held lock with the same
220
+ // name and grants the request immediately, preempting any queued requests.
221
+ // The previous holder's callback continues running to completion but no
222
+ // longer holds the lock for exclusion purposes.
223
+ //
224
+ // See: https://github.com/supabase/supabase/issues/42505
225
+ if (internals.debug) {
226
+ console.log(
227
+ '@supabase/gotrue-js: navigatorLock: acquire timeout, recovering by stealing lock',
228
+ name
229
+ )
230
+ }
218
231
 
219
- return await Promise.resolve().then(() =>
220
- globalThis.navigator.locks.request(
221
- name,
222
- {
223
- mode: 'exclusive',
224
- steal: true,
225
- },
226
- async (lock) => {
227
- if (lock) {
228
- if (internals.debug) {
229
- console.log(
230
- '@supabase/gotrue-js: navigatorLock: recovered (stolen)',
231
- name,
232
- lock.name
233
- )
234
- }
232
+ console.warn(
233
+ `@supabase/gotrue-js: Lock "${name}" was not released within ${acquireTimeout}ms. ` +
234
+ 'This may indicate an orphaned lock from a component unmount (e.g., React Strict Mode). ' +
235
+ 'Forcefully acquiring the lock to recover.'
236
+ )
235
237
 
236
- try {
237
- return await fn()
238
- } finally {
238
+ return await Promise.resolve().then(() =>
239
+ globalThis.navigator.locks.request(
240
+ name,
241
+ {
242
+ mode: 'exclusive',
243
+ steal: true,
244
+ },
245
+ async (lock) => {
246
+ if (lock) {
239
247
  if (internals.debug) {
240
248
  console.log(
241
- '@supabase/gotrue-js: navigatorLock: released (stolen)',
249
+ '@supabase/gotrue-js: navigatorLock: recovered (stolen)',
242
250
  name,
243
251
  lock.name
244
252
  )
245
253
  }
254
+
255
+ try {
256
+ return await fn()
257
+ } finally {
258
+ if (internals.debug) {
259
+ console.log(
260
+ '@supabase/gotrue-js: navigatorLock: released (stolen)',
261
+ name,
262
+ lock.name
263
+ )
264
+ }
265
+ }
266
+ } else {
267
+ // This should not happen with steal: true, but handle gracefully.
268
+ console.warn(
269
+ '@supabase/gotrue-js: Navigator LockManager returned null lock even with steal: true'
270
+ )
271
+ return await fn()
246
272
  }
247
- } else {
248
- // This should not happen with steal: true, but handle gracefully.
249
- console.warn(
250
- '@supabase/gotrue-js: Navigator LockManager returned null lock even with steal: true'
251
- )
252
- return await fn()
253
273
  }
254
- }
274
+ )
275
+ )
276
+ } else {
277
+ // We HELD the lock but another request stole it from us.
278
+ // Per the Web Locks spec, our fn() callback is still running as an
279
+ // orphaned background task — do NOT steal back. Stealing back would
280
+ // cause a cascade (A steals B, B steals A, ...) and run fn() a second
281
+ // time concurrently, corrupting auth state.
282
+ // Convert to a typed error so callers (e.g. _autoRefreshTokenTick)
283
+ // can handle/filter it without it leaking to Sentry as a raw AbortError.
284
+ if (internals.debug) {
285
+ console.log(
286
+ '@supabase/gotrue-js: navigatorLock: lock was stolen by another request',
287
+ name
288
+ )
289
+ }
290
+
291
+ throw new NavigatorLockAcquireTimeoutError(
292
+ `Lock "${name}" was released because another request stole it`
255
293
  )
256
- )
294
+ }
257
295
  }
258
296
 
259
297
  throw e