@supabase/realtime-js 2.79.1-canary.2 → 2.80.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/README.md +37 -5
- package/dist/main/RealtimeChannel.d.ts +99 -0
- package/dist/main/RealtimeChannel.d.ts.map +1 -1
- package/dist/main/RealtimeChannel.js +61 -40
- package/dist/main/RealtimeChannel.js.map +1 -1
- package/dist/main/RealtimeClient.d.ts.map +1 -1
- package/dist/main/RealtimeClient.js +7 -54
- package/dist/main/RealtimeClient.js.map +1 -1
- package/dist/main/index.js +5 -40
- package/dist/main/index.js.map +1 -1
- package/dist/main/lib/constants.d.ts +2 -2
- package/dist/main/lib/constants.d.ts.map +1 -1
- package/dist/main/lib/transformers.d.ts.map +1 -1
- package/dist/main/lib/transformers.js +14 -4
- package/dist/main/lib/transformers.js.map +1 -1
- 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/RealtimeChannel.d.ts +99 -0
- package/dist/module/RealtimeChannel.d.ts.map +1 -1
- package/dist/module/RealtimeChannel.js +56 -0
- package/dist/module/RealtimeChannel.js.map +1 -1
- package/dist/module/RealtimeClient.d.ts.map +1 -1
- package/dist/module/RealtimeClient.js +2 -15
- package/dist/module/RealtimeClient.js.map +1 -1
- package/dist/module/lib/constants.d.ts +2 -2
- package/dist/module/lib/constants.d.ts.map +1 -1
- package/dist/module/lib/transformers.d.ts.map +1 -1
- package/dist/module/lib/transformers.js +14 -4
- package/dist/module/lib/transformers.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 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +7 -6
- package/src/RealtimeChannel.ts +158 -1
- package/src/RealtimeClient.ts +2 -16
- package/src/lib/transformers.ts +17 -4
- package/src/lib/version.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supabase/realtime-js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.80.0",
|
|
4
4
|
"description": "Listen to realtime updates to your PostgreSQL database",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"realtime",
|
|
@@ -28,9 +28,7 @@
|
|
|
28
28
|
"author": "Supabase",
|
|
29
29
|
"license": "MIT",
|
|
30
30
|
"scripts": {
|
|
31
|
-
"
|
|
32
|
-
"format": "prettier --write \"{src,test}/**/*.ts\"",
|
|
33
|
-
"build": "npm run clean && npm run format && npm run build:main && npm run build:module",
|
|
31
|
+
"build": "npm run build:main && npm run build:module",
|
|
34
32
|
"build:main": "tsc -p tsconfig.json",
|
|
35
33
|
"build:module": "tsc -p tsconfig.module.json",
|
|
36
34
|
"test": "vitest run",
|
|
@@ -43,9 +41,9 @@
|
|
|
43
41
|
},
|
|
44
42
|
"dependencies": {
|
|
45
43
|
"@types/phoenix": "^1.6.6",
|
|
46
|
-
"ws": "^8.18.2",
|
|
47
44
|
"@types/ws": "^8.18.1",
|
|
48
|
-
"
|
|
45
|
+
"tslib": "2.8.1",
|
|
46
|
+
"ws": "^8.18.2"
|
|
49
47
|
},
|
|
50
48
|
"devDependencies": {
|
|
51
49
|
"@arethetypeswrong/cli": "^0.16.4",
|
|
@@ -56,5 +54,8 @@
|
|
|
56
54
|
"mock-socket": "^9.3.1",
|
|
57
55
|
"nyc": "^15.1.0",
|
|
58
56
|
"web-worker": "1.2.0"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=20.0.0"
|
|
59
60
|
}
|
|
60
61
|
}
|
package/src/RealtimeChannel.ts
CHANGED
|
@@ -11,13 +11,19 @@ import type {
|
|
|
11
11
|
import * as Transformers from './lib/transformers'
|
|
12
12
|
import { httpEndpointURL } from './lib/transformers'
|
|
13
13
|
|
|
14
|
+
type ReplayOption = {
|
|
15
|
+
since: number
|
|
16
|
+
limit?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
export type RealtimeChannelOptions = {
|
|
15
20
|
config: {
|
|
16
21
|
/**
|
|
17
22
|
* self option enables client to receive message it broadcast
|
|
18
23
|
* ack option instructs server to acknowledge that broadcast message was received
|
|
24
|
+
* replay option instructs server to replay broadcast messages
|
|
19
25
|
*/
|
|
20
|
-
broadcast?: { self?: boolean; ack?: boolean }
|
|
26
|
+
broadcast?: { self?: boolean; ack?: boolean; replay?: ReplayOption }
|
|
21
27
|
/**
|
|
22
28
|
* key option is used to track presence payload across clients
|
|
23
29
|
*/
|
|
@@ -29,6 +35,41 @@ export type RealtimeChannelOptions = {
|
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
37
|
|
|
38
|
+
type RealtimeChangesPayloadBase = {
|
|
39
|
+
schema: string
|
|
40
|
+
table: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type RealtimeBroadcastChangesPayloadBase = RealtimeChangesPayloadBase & {
|
|
44
|
+
id: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type RealtimeBroadcastInsertPayload<T extends { [key: string]: any }> =
|
|
48
|
+
RealtimeBroadcastChangesPayloadBase & {
|
|
49
|
+
operation: `${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.INSERT}`
|
|
50
|
+
record: T
|
|
51
|
+
old_record: null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type RealtimeBroadcastUpdatePayload<T extends { [key: string]: any }> =
|
|
55
|
+
RealtimeBroadcastChangesPayloadBase & {
|
|
56
|
+
operation: `${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.UPDATE}`
|
|
57
|
+
record: T
|
|
58
|
+
old_record: T
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type RealtimeBroadcastDeletePayload<T extends { [key: string]: any }> =
|
|
62
|
+
RealtimeBroadcastChangesPayloadBase & {
|
|
63
|
+
operation: `${REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.DELETE}`
|
|
64
|
+
record: null
|
|
65
|
+
old_record: T
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type RealtimeBroadcastPayload<T extends { [key: string]: any }> =
|
|
69
|
+
| RealtimeBroadcastInsertPayload<T>
|
|
70
|
+
| RealtimeBroadcastUpdatePayload<T>
|
|
71
|
+
| RealtimeBroadcastDeletePayload<T>
|
|
72
|
+
|
|
32
73
|
type RealtimePostgresChangesPayloadBase = {
|
|
33
74
|
schema: string
|
|
34
75
|
table: string
|
|
@@ -203,6 +244,10 @@ export default class RealtimeChannel {
|
|
|
203
244
|
|
|
204
245
|
this.broadcastEndpointURL = httpEndpointURL(this.socket.endPoint)
|
|
205
246
|
this.private = this.params.config.private || false
|
|
247
|
+
|
|
248
|
+
if (!this.private && this.params.config?.broadcast?.replay) {
|
|
249
|
+
throw `tried to use replay on public channel '${this.topic}'. It must be a private channel.`
|
|
250
|
+
}
|
|
206
251
|
}
|
|
207
252
|
|
|
208
253
|
/** Subscribe registers your client with the server */
|
|
@@ -386,6 +431,10 @@ export default class RealtimeChannel {
|
|
|
386
431
|
callback: (payload: {
|
|
387
432
|
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`
|
|
388
433
|
event: string
|
|
434
|
+
meta?: {
|
|
435
|
+
replayed?: boolean
|
|
436
|
+
id: string
|
|
437
|
+
}
|
|
389
438
|
[key: string]: any
|
|
390
439
|
}) => void
|
|
391
440
|
): RealtimeChannel
|
|
@@ -395,9 +444,49 @@ export default class RealtimeChannel {
|
|
|
395
444
|
callback: (payload: {
|
|
396
445
|
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`
|
|
397
446
|
event: string
|
|
447
|
+
meta?: {
|
|
448
|
+
replayed?: boolean
|
|
449
|
+
id: string
|
|
450
|
+
}
|
|
398
451
|
payload: T
|
|
399
452
|
}) => void
|
|
400
453
|
): RealtimeChannel
|
|
454
|
+
on<T extends Record<string, unknown>>(
|
|
455
|
+
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`,
|
|
456
|
+
filter: { event: REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.ALL },
|
|
457
|
+
callback: (payload: {
|
|
458
|
+
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`
|
|
459
|
+
event: REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.ALL
|
|
460
|
+
payload: RealtimeBroadcastPayload<T>
|
|
461
|
+
}) => void
|
|
462
|
+
): RealtimeChannel
|
|
463
|
+
on<T extends { [key: string]: any }>(
|
|
464
|
+
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`,
|
|
465
|
+
filter: { event: REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.INSERT },
|
|
466
|
+
callback: (payload: {
|
|
467
|
+
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`
|
|
468
|
+
event: REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.INSERT
|
|
469
|
+
payload: RealtimeBroadcastInsertPayload<T>
|
|
470
|
+
}) => void
|
|
471
|
+
): RealtimeChannel
|
|
472
|
+
on<T extends { [key: string]: any }>(
|
|
473
|
+
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`,
|
|
474
|
+
filter: { event: REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.UPDATE },
|
|
475
|
+
callback: (payload: {
|
|
476
|
+
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`
|
|
477
|
+
event: REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.UPDATE
|
|
478
|
+
payload: RealtimeBroadcastUpdatePayload<T>
|
|
479
|
+
}) => void
|
|
480
|
+
): RealtimeChannel
|
|
481
|
+
on<T extends { [key: string]: any }>(
|
|
482
|
+
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`,
|
|
483
|
+
filter: { event: REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.DELETE },
|
|
484
|
+
callback: (payload: {
|
|
485
|
+
type: `${REALTIME_LISTEN_TYPES.BROADCAST}`
|
|
486
|
+
event: REALTIME_POSTGRES_CHANGES_LISTEN_EVENT.DELETE
|
|
487
|
+
payload: RealtimeBroadcastDeletePayload<T>
|
|
488
|
+
}) => void
|
|
489
|
+
): RealtimeChannel
|
|
401
490
|
on<T extends { [key: string]: any }>(
|
|
402
491
|
type: `${REALTIME_LISTEN_TYPES.SYSTEM}`,
|
|
403
492
|
filter: {},
|
|
@@ -417,6 +506,68 @@ export default class RealtimeChannel {
|
|
|
417
506
|
}
|
|
418
507
|
return this._on(type, filter, callback)
|
|
419
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* Sends a broadcast message explicitly via REST API.
|
|
511
|
+
*
|
|
512
|
+
* This method always uses the REST API endpoint regardless of WebSocket connection state.
|
|
513
|
+
* Useful when you want to guarantee REST delivery or when gradually migrating from implicit REST fallback.
|
|
514
|
+
*
|
|
515
|
+
* @param event The name of the broadcast event
|
|
516
|
+
* @param payload Payload to be sent (required)
|
|
517
|
+
* @param opts Options including timeout
|
|
518
|
+
* @returns Promise resolving to object with success status, and error details if failed
|
|
519
|
+
*/
|
|
520
|
+
async httpSend(
|
|
521
|
+
event: string,
|
|
522
|
+
payload: any,
|
|
523
|
+
opts: { timeout?: number } = {}
|
|
524
|
+
): Promise<{ success: true } | { success: false; status: number; error: string }> {
|
|
525
|
+
const authorization = this.socket.accessTokenValue
|
|
526
|
+
? `Bearer ${this.socket.accessTokenValue}`
|
|
527
|
+
: ''
|
|
528
|
+
|
|
529
|
+
if (payload === undefined || payload === null) {
|
|
530
|
+
return Promise.reject('Payload is required for httpSend()')
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const options = {
|
|
534
|
+
method: 'POST',
|
|
535
|
+
headers: {
|
|
536
|
+
Authorization: authorization,
|
|
537
|
+
apikey: this.socket.apiKey ? this.socket.apiKey : '',
|
|
538
|
+
'Content-Type': 'application/json',
|
|
539
|
+
},
|
|
540
|
+
body: JSON.stringify({
|
|
541
|
+
messages: [
|
|
542
|
+
{
|
|
543
|
+
topic: this.subTopic,
|
|
544
|
+
event,
|
|
545
|
+
payload: payload,
|
|
546
|
+
private: this.private,
|
|
547
|
+
},
|
|
548
|
+
],
|
|
549
|
+
}),
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const response = await this._fetchWithTimeout(
|
|
553
|
+
this.broadcastEndpointURL,
|
|
554
|
+
options,
|
|
555
|
+
opts.timeout ?? this.timeout
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
if (response.status === 202) {
|
|
559
|
+
return { success: true }
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
let errorMessage = response.statusText
|
|
563
|
+
try {
|
|
564
|
+
const errorBody = await response.json()
|
|
565
|
+
errorMessage = errorBody.error || errorBody.message || errorMessage
|
|
566
|
+
} catch {}
|
|
567
|
+
|
|
568
|
+
return Promise.reject(new Error(errorMessage))
|
|
569
|
+
}
|
|
570
|
+
|
|
420
571
|
/**
|
|
421
572
|
* Sends a message into the channel.
|
|
422
573
|
*
|
|
@@ -436,6 +587,12 @@ export default class RealtimeChannel {
|
|
|
436
587
|
opts: { [key: string]: any } = {}
|
|
437
588
|
): Promise<RealtimeChannelSendResponse> {
|
|
438
589
|
if (!this._canPush() && args.type === 'broadcast') {
|
|
590
|
+
console.warn(
|
|
591
|
+
'Realtime send() is automatically falling back to REST API. ' +
|
|
592
|
+
'This behavior will be deprecated in the future. ' +
|
|
593
|
+
'Please use httpSend() explicitly for REST delivery.'
|
|
594
|
+
)
|
|
595
|
+
|
|
439
596
|
const { event, payload: endpoint_payload } = args
|
|
440
597
|
const authorization = this.socket.accessTokenValue
|
|
441
598
|
? `Bearer ${this.socket.accessTokenValue}`
|
package/src/RealtimeClient.ts
CHANGED
|
@@ -465,24 +465,10 @@ export default class RealtimeClient {
|
|
|
465
465
|
* @internal
|
|
466
466
|
*/
|
|
467
467
|
_resolveFetch = (customFetch?: Fetch): Fetch => {
|
|
468
|
-
let _fetch: Fetch
|
|
469
468
|
if (customFetch) {
|
|
470
|
-
|
|
471
|
-
} else if (typeof fetch === 'undefined') {
|
|
472
|
-
// Node.js environment without native fetch
|
|
473
|
-
_fetch = (...args) =>
|
|
474
|
-
import('@supabase/node-fetch' as any)
|
|
475
|
-
.then(({ default: fetch }) => fetch(...args))
|
|
476
|
-
.catch((error) => {
|
|
477
|
-
throw new Error(
|
|
478
|
-
`Failed to load @supabase/node-fetch: ${error.message}. ` +
|
|
479
|
-
`This is required for HTTP requests in Node.js environments without native fetch.`
|
|
480
|
-
)
|
|
481
|
-
})
|
|
482
|
-
} else {
|
|
483
|
-
_fetch = fetch
|
|
469
|
+
return (...args) => customFetch(...args)
|
|
484
470
|
}
|
|
485
|
-
return (...args) =>
|
|
471
|
+
return (...args) => fetch(...args)
|
|
486
472
|
}
|
|
487
473
|
|
|
488
474
|
/**
|
package/src/lib/transformers.ts
CHANGED
|
@@ -251,8 +251,21 @@ export const toTimestampString = (value: RecordValue): RecordValue => {
|
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
export const httpEndpointURL = (socketUrl: string): string => {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
const wsUrl = new URL(socketUrl)
|
|
255
|
+
|
|
256
|
+
wsUrl.protocol = wsUrl.protocol.replace(/^ws/i, 'http')
|
|
257
|
+
|
|
258
|
+
wsUrl.pathname = wsUrl.pathname
|
|
259
|
+
.replace(/\/+$/, '') // remove all trailing slashes
|
|
260
|
+
.replace(/\/socket\/websocket$/i, '') // remove the socket/websocket path
|
|
261
|
+
.replace(/\/socket$/i, '') // remove the socket path
|
|
262
|
+
.replace(/\/websocket$/i, '') // remove the websocket path
|
|
263
|
+
|
|
264
|
+
if (wsUrl.pathname === '' || wsUrl.pathname === '/') {
|
|
265
|
+
wsUrl.pathname = '/api/broadcast'
|
|
266
|
+
} else {
|
|
267
|
+
wsUrl.pathname = wsUrl.pathname + '/api/broadcast'
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return wsUrl.href
|
|
258
271
|
}
|
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.
|
|
7
|
+
export const version = '2.80.0'
|