@supabase/gotrue-js 2.107.0-canary.5 → 2.107.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/lib/version.d.ts +1 -1
- package/dist/main/lib/version.d.ts.map +1 -1
- package/dist/main/lib/version.js +1 -1
- package/dist/main/lib/version.js.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.d.ts.map +1 -1
- package/dist/module/lib/version.js +1 -1
- package/dist/module/lib/version.js.map +1 -1
- package/dist/tsconfig.module.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/migrations/lockless-coordination.md +66 -0
- package/package.json +1 -1
- package/src/lib/version.ts +1 -1
|
@@ -58,6 +58,72 @@ if (isAuthRefreshDiscardedError(error)) {
|
|
|
58
58
|
- **`onAuthStateChange` async callbacks** that call `getUser`, `setSession`, or read the session from inside the callback are now safe on the default path (previously deadlocked through the lock). One residual hazard remains: calling `refreshSession` (or anything routing through `_callRefreshToken`) from inside a `TOKEN_REFRESHED` handler still deadlocks via `refreshingDeferred`. The `@deprecated` marker on the async overload is kept with its reason updated to point at this specific case.
|
|
59
59
|
- **Subscriber timing on the default path:** subscribers stay awaited; same as before. What changes is that `signOut` no longer waits for an in-flight refresh's HTTP and continuation to finish before its own fetch goes out. Both fetches now run concurrently, and the commit guard keeps storage consistent.
|
|
60
60
|
|
|
61
|
+
## Timing & concurrency notes for downstream consumers
|
|
62
|
+
|
|
63
|
+
Removing the default `_acquireLock(...)` wrapper changes the _microtask shape_ of `getSession`, `getUser`, `refreshSession`, `setSession`, `signOut`, `_initialize`, and `_reauthenticate`. Application behavior is unchanged — these methods still return the same values — but the await chain is shorter.
|
|
64
|
+
|
|
65
|
+
### What changed in the await chain
|
|
66
|
+
|
|
67
|
+
Previously, each of those methods looked like:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
return await this._acquireLock(this.lockAcquireTimeout, async () => {
|
|
71
|
+
return await this._getUser()
|
|
72
|
+
})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`_acquireLock` awaited `navigator.locks.request` (browser) or the in-process `processLock` (Node). That added a handful of microtasks before the inner operation ran. On the lockless default path, the wrapper is skipped and the inner operation runs directly:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
if (this.lock) {
|
|
79
|
+
return await this._acquireLock(this.lockAcquireTimeout, async () => {
|
|
80
|
+
return await this._getUser()
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
return await this._getUser()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Downstream impact via `fetchWithAuth`
|
|
87
|
+
|
|
88
|
+
`supabase-js` wraps the user's `fetch` via `fetchWithAuth` (in `packages/core/supabase-js/src/SupabaseClient.ts`), which awaits `_getAccessToken()` before every PostgREST, Storage, and Functions request. With the shorter pre-fetch await chain, concurrent client calls — for example `Promise.all([supabase.rpc(...), supabase.rpc(...)])` or `Promise.all(rows.map((r) => supabase.from(...).insert(...)))` — may reach the network layer in a different micro-order than they did on v2.106 and earlier.
|
|
89
|
+
|
|
90
|
+
### What this can surface as
|
|
91
|
+
|
|
92
|
+
Tests that use order-sensitive mocks (nock, MSW, or any interceptor that matches requests in registration order) against parallel client calls may flip. A concrete example from the wild: a downstream worker repo registered two `nock(URL).post('/rest/v1/rpc/queue_job', body => expect(body).toMatchInlineSnapshot(...)).reply(200)` interceptors back-to-back, one expecting database `333`, the other expecting database `222`, and relied on the calls arriving in that order. The application code dispatched both via `Promise.all(replicas.map((r) => supabase.rpc('queue_job', ...)))`. On v2.107 the arrival order flipped, the first interceptor's body matcher ran against the wrong payload, vitest raised `toMatchInlineSnapshot with different snapshots cannot be called at the same location`, and the unmatched interceptor caused a "pending mocks left" failure at teardown.
|
|
93
|
+
|
|
94
|
+
The application behavior was correct in both versions: both RPCs completed, both rows ended up in the queue. Only the _test_ depended on an ordering that was never guaranteed.
|
|
95
|
+
|
|
96
|
+
### Recommended fix pattern
|
|
97
|
+
|
|
98
|
+
Make mocks order-independent. Two common shapes:
|
|
99
|
+
|
|
100
|
+
1. **Branch the body matcher on a discriminator field.** Register one interceptor with `.times(N)`; inside the body matcher, look at a field on the request body (e.g. an `id`) and assert against the expected payload for that id.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
const expected: Record<number, unknown> = {
|
|
104
|
+
222: {
|
|
105
|
+
/* expected body for replica 222 */
|
|
106
|
+
},
|
|
107
|
+
333: {
|
|
108
|
+
/* expected body for replica 333 */
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
nock(URL)
|
|
113
|
+
.post('/path', (body) => {
|
|
114
|
+
expect(body).toStrictEqual(expected[body.id])
|
|
115
|
+
return true
|
|
116
|
+
})
|
|
117
|
+
.times(2)
|
|
118
|
+
.reply(200)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
2. **Capture and assert as a set.** Push each received body into an array from the matcher, return `true` to accept, then after the parallel block resolves assert the array's _contents_ (e.g. via `expect(received).toEqual(expect.arrayContaining([...]))`) without pinning order.
|
|
122
|
+
|
|
123
|
+
Do not pin behavior to lock-induced delays. They were incidental, not a guarantee — and they may shift again in future patch releases as internal awaits are refactored.
|
|
124
|
+
|
|
125
|
+
The custom-`lock` opt-in path retains the old await shape and is unaffected by this section.
|
|
126
|
+
|
|
61
127
|
## Migration steps
|
|
62
128
|
|
|
63
129
|
### If you do not pass a custom `lock` (most users)
|
package/package.json
CHANGED
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.107.0
|
|
7
|
+
export const version = '2.107.0'
|