@supabase/realtime-js 2.108.2-beta.0 → 2.108.2-beta.5
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/RealtimeChannel.d.ts +10 -0
- package/dist/main/RealtimeChannel.d.ts.map +1 -1
- package/dist/main/RealtimeChannel.js +53 -1
- package/dist/main/RealtimeChannel.js.map +1 -1
- package/dist/main/lib/constants.d.ts +2 -2
- package/dist/main/lib/version.d.ts +1 -1
- package/dist/main/lib/version.js +1 -1
- package/dist/module/RealtimeChannel.d.ts +10 -0
- package/dist/module/RealtimeChannel.d.ts.map +1 -1
- package/dist/module/RealtimeChannel.js +53 -1
- package/dist/module/RealtimeChannel.js.map +1 -1
- package/dist/module/lib/constants.d.ts +2 -2
- 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/httpsend-server-version.md +88 -0
- package/package.json +1 -1
- package/src/RealtimeChannel.ts +68 -1
- package/src/lib/version.ts +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# `httpSend()` server version requirement
|
|
2
|
+
|
|
3
|
+
**Since:** v2.107.0
|
|
4
|
+
**Applies to:** anyone calling `RealtimeChannel.httpSend()` (or `RealtimeChannel.broadcast()` configured to use HTTP)
|
|
5
|
+
|
|
6
|
+
`httpSend()` sends broadcast events through a per-event REST endpoint:
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
POST /api/broadcast/:topic/events/:event
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
This endpoint was added in **Realtime server v2.97.0** ([supabase/realtime#1864](https://github.com/supabase/realtime/pull/1864)). It also enables binary broadcast payloads (`application/octet-stream`), which the older batch endpoint does not support.
|
|
13
|
+
|
|
14
|
+
## What changed
|
|
15
|
+
|
|
16
|
+
- `httpSend()` calls the new per-event endpoint and expects HTTP `202`.
|
|
17
|
+
- On `404`, the client now rejects with a message that names the requirement and the escape hatches (see below) instead of returning the generic `Not Found` text from the server.
|
|
18
|
+
- The original `RealtimeChannel.send()` (and its REST fallback) still target the older `POST /api/broadcast` batch endpoint and are unaffected.
|
|
19
|
+
|
|
20
|
+
## Who is affected
|
|
21
|
+
|
|
22
|
+
You are affected if **all** of the following are true:
|
|
23
|
+
|
|
24
|
+
1. You upgraded `@supabase/realtime-js` (or `@supabase/supabase-js`) to **v2.107.0 or later**, **and**
|
|
25
|
+
2. You call `httpSend()` (or `broadcast()` with `type: 'broadcast'` routed through HTTP), **and**
|
|
26
|
+
3. Your Realtime server is **older than v2.97.0**.
|
|
27
|
+
|
|
28
|
+
If you only use the WebSocket `send()` API, or your Realtime server is already on v2.97.0+, nothing changes for you.
|
|
29
|
+
|
|
30
|
+
## How to verify the server version
|
|
31
|
+
|
|
32
|
+
The Realtime server does not currently emit a version header, so the easiest checks are:
|
|
33
|
+
|
|
34
|
+
- **Hosted Supabase:** version is rolled forward continuously and is on v2.97.0+.
|
|
35
|
+
- **Local development with the Supabase CLI:** recent CLI versions bundle Realtime v2.97.0+. Update the CLI to the latest stable.
|
|
36
|
+
- **Self-hosted:** check the `image:` tag of the Realtime container in your `docker-compose.yml`.
|
|
37
|
+
|
|
38
|
+
## What to do
|
|
39
|
+
|
|
40
|
+
### If you are on a recent Supabase CLI
|
|
41
|
+
|
|
42
|
+
You should already be on a compatible Realtime version. If you still see the 404 error, update the CLI:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# macOS / Homebrew
|
|
46
|
+
brew upgrade supabase/tap/supabase
|
|
47
|
+
|
|
48
|
+
# npm
|
|
49
|
+
npm install -g supabase
|
|
50
|
+
|
|
51
|
+
# scoop / etc — see https://supabase.com/docs/guides/local-development
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then restart the local Supabase stack.
|
|
55
|
+
|
|
56
|
+
### If you need to pin a specific Realtime version locally
|
|
57
|
+
|
|
58
|
+
The CLI honors a per-project pin file. Create the file with the desired image tag:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
mkdir -p supabase/.temp
|
|
62
|
+
echo "v2.97.3" > supabase/.temp/realtime-version
|
|
63
|
+
supabase stop && supabase start
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
(This is the same mechanism the `@supabase/supabase-js` test harness uses internally.)
|
|
67
|
+
|
|
68
|
+
### If you self-host
|
|
69
|
+
|
|
70
|
+
Bump the Realtime image in your deployment to `v2.97.3` or newer:
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
services:
|
|
74
|
+
realtime:
|
|
75
|
+
image: supabase/realtime:v2.97.3
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### If you cannot update the server right now
|
|
79
|
+
|
|
80
|
+
Downgrade `@supabase/realtime-js` (and `@supabase/supabase-js`) back to **v2.106.x**, which only uses the older `POST /api/broadcast` batch endpoint:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install @supabase/supabase-js@2.106.2
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Why the message is more specific now
|
|
87
|
+
|
|
88
|
+
Prior to this release, a 404 from the new endpoint surfaced as a plain `Not Found` error, which was hard to act on. The client now rejects with a message that points at this migration file and the escape hatches above.
|
package/package.json
CHANGED
package/src/RealtimeChannel.ts
CHANGED
|
@@ -179,6 +179,9 @@ export default class RealtimeChannel {
|
|
|
179
179
|
broadcastEndpointURL: string
|
|
180
180
|
private: boolean
|
|
181
181
|
presence: RealtimePresence
|
|
182
|
+
private _postgresChangesSystemReady = false
|
|
183
|
+
private _subscribeCallback: ((status: REALTIME_SUBSCRIBE_STATES, err?: Error) => void) | null =
|
|
184
|
+
null
|
|
182
185
|
/** @internal */
|
|
183
186
|
channelAdapter: ChannelAdapter
|
|
184
187
|
|
|
@@ -253,8 +256,22 @@ export default class RealtimeChannel {
|
|
|
253
256
|
|
|
254
257
|
this.channelAdapter = new ChannelAdapter(this.socket.socketAdapter, topic, this.params)
|
|
255
258
|
this.presence = new RealtimePresence(this)
|
|
259
|
+
this.channelAdapter.on(REALTIME_LISTEN_TYPES.SYSTEM, (payload: unknown) => {
|
|
260
|
+
if (
|
|
261
|
+
payload &&
|
|
262
|
+
typeof payload === 'object' &&
|
|
263
|
+
'extension' in payload &&
|
|
264
|
+
payload.extension === REALTIME_LISTEN_TYPES.POSTGRES_CHANGES &&
|
|
265
|
+
'status' in payload &&
|
|
266
|
+
payload.status === 'ok'
|
|
267
|
+
) {
|
|
268
|
+
this._postgresChangesSystemReady = true
|
|
269
|
+
this._emitSubscribed()
|
|
270
|
+
}
|
|
271
|
+
})
|
|
256
272
|
|
|
257
273
|
this._onClose(() => {
|
|
274
|
+
this._resetSubscribeState()
|
|
258
275
|
this.socket._remove(this)
|
|
259
276
|
})
|
|
260
277
|
|
|
@@ -277,6 +294,10 @@ export default class RealtimeChannel {
|
|
|
277
294
|
* Log the full `err` so its `cause`, `name`, and any structured fields aren't hidden
|
|
278
295
|
* behind `err.message`.
|
|
279
296
|
*
|
|
297
|
+
* For channels that only bind `postgres_changes` callbacks, `SUBSCRIBED` is emitted after the
|
|
298
|
+
* server confirms the Postgres changefeed is ready. Channels with `broadcast` or `presence`
|
|
299
|
+
* callbacks keep the existing `SUBSCRIBED` timing.
|
|
300
|
+
*
|
|
280
301
|
* @category Realtime
|
|
281
302
|
*
|
|
282
303
|
* @example Handling errors
|
|
@@ -297,6 +318,7 @@ export default class RealtimeChannel {
|
|
|
297
318
|
this.socket.connect()
|
|
298
319
|
}
|
|
299
320
|
if (this.channelAdapter.isClosed()) {
|
|
321
|
+
this._resetSubscribeState()
|
|
300
322
|
const {
|
|
301
323
|
config: { broadcast, presence, private: isPrivate },
|
|
302
324
|
} = this.params
|
|
@@ -344,11 +366,13 @@ export default class RealtimeChannel {
|
|
|
344
366
|
this._updatePostgresBindings(postgres_changes, callback)
|
|
345
367
|
})
|
|
346
368
|
.receive('error', (error: { [key: string]: any }) => {
|
|
369
|
+
this._resetSubscribeState()
|
|
347
370
|
this.state = CHANNEL_STATES.errored
|
|
348
371
|
const message = Object.values(error).join(', ') || 'error'
|
|
349
372
|
callback?.(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, new Error(message, { cause: error }))
|
|
350
373
|
})
|
|
351
374
|
.receive('timeout', () => {
|
|
375
|
+
this._resetSubscribeState()
|
|
352
376
|
callback?.(REALTIME_SUBSCRIBE_STATES.TIMED_OUT)
|
|
353
377
|
})
|
|
354
378
|
}
|
|
@@ -396,7 +420,7 @@ export default class RealtimeChannel {
|
|
|
396
420
|
this.bindings.postgres_changes = newPostgresBindings
|
|
397
421
|
|
|
398
422
|
if (this.state != CHANNEL_STATES.errored && callback) {
|
|
399
|
-
callback
|
|
423
|
+
this._onSubscribeOk(callback)
|
|
400
424
|
}
|
|
401
425
|
}
|
|
402
426
|
|
|
@@ -803,6 +827,16 @@ export default class RealtimeChannel {
|
|
|
803
827
|
return { success: true }
|
|
804
828
|
}
|
|
805
829
|
|
|
830
|
+
if (response.status === 404) {
|
|
831
|
+
return Promise.reject(
|
|
832
|
+
new Error(
|
|
833
|
+
'httpSend() requires Realtime server v2.97.0 or newer; the endpoint returned 404. ' +
|
|
834
|
+
'Update your Supabase CLI to a recent version, or upgrade the Realtime server in your self-hosted setup. ' +
|
|
835
|
+
'See https://github.com/supabase/supabase-js/blob/master/packages/core/realtime-js/migrations/httpsend-server-version.md'
|
|
836
|
+
)
|
|
837
|
+
)
|
|
838
|
+
}
|
|
839
|
+
|
|
806
840
|
let errorMessage = response.statusText
|
|
807
841
|
try {
|
|
808
842
|
const errorBody = await response.json()
|
|
@@ -1121,6 +1155,39 @@ export default class RealtimeChannel {
|
|
|
1121
1155
|
return normalizedServer === normalizedClient
|
|
1122
1156
|
}
|
|
1123
1157
|
|
|
1158
|
+
private _onSubscribeOk(callback: (status: REALTIME_SUBSCRIBE_STATES, err?: Error) => void) {
|
|
1159
|
+
if (!this._shouldWaitForPostgresChangesSystem()) {
|
|
1160
|
+
callback(REALTIME_SUBSCRIBE_STATES.SUBSCRIBED)
|
|
1161
|
+
return
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
this._subscribeCallback = callback
|
|
1165
|
+
this._emitSubscribed()
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
private _emitSubscribed() {
|
|
1169
|
+
if (!this._subscribeCallback || !this._postgresChangesSystemReady) {
|
|
1170
|
+
return
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
const callback = this._subscribeCallback
|
|
1174
|
+
this._subscribeCallback = null
|
|
1175
|
+
callback(REALTIME_SUBSCRIBE_STATES.SUBSCRIBED)
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
private _resetSubscribeState() {
|
|
1179
|
+
this._postgresChangesSystemReady = false
|
|
1180
|
+
this._subscribeCallback = null
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
private _shouldWaitForPostgresChangesSystem() {
|
|
1184
|
+
return (
|
|
1185
|
+
(this.bindings.postgres_changes?.length ?? 0) > 0 &&
|
|
1186
|
+
(this.bindings.broadcast?.length ?? 0) === 0 &&
|
|
1187
|
+
(this.bindings.presence?.length ?? 0) === 0
|
|
1188
|
+
)
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1124
1191
|
/** @internal */
|
|
1125
1192
|
private _getPayloadRecords(payload: any) {
|
|
1126
1193
|
const records = {
|
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.108.2-beta.
|
|
7
|
+
export const version = '2.108.2-beta.5'
|