@supabase/realtime-js 1.4.3 → 1.4.6

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 (33) hide show
  1. package/dist/main/RealtimeChannel.d.ts +69 -0
  2. package/dist/main/RealtimeChannel.d.ts.map +1 -0
  3. package/dist/main/RealtimeChannel.js +200 -0
  4. package/dist/main/RealtimeChannel.js.map +1 -0
  5. package/dist/main/RealtimeClient.d.ts +5 -2
  6. package/dist/main/RealtimeClient.d.ts.map +1 -1
  7. package/dist/main/RealtimeClient.js +39 -3
  8. package/dist/main/RealtimeClient.js.map +1 -1
  9. package/dist/main/RealtimePresence.d.ts +3 -3
  10. package/dist/main/RealtimePresence.d.ts.map +1 -1
  11. package/dist/main/RealtimePresence.js +2 -2
  12. package/dist/main/RealtimePresence.js.map +1 -1
  13. package/dist/main/lib/version.d.ts +1 -1
  14. package/dist/main/lib/version.js +1 -1
  15. package/dist/module/RealtimeChannel.d.ts +69 -0
  16. package/dist/module/RealtimeChannel.d.ts.map +1 -0
  17. package/dist/module/RealtimeChannel.js +194 -0
  18. package/dist/module/RealtimeChannel.js.map +1 -0
  19. package/dist/module/RealtimeClient.d.ts +5 -2
  20. package/dist/module/RealtimeClient.d.ts.map +1 -1
  21. package/dist/module/RealtimeClient.js +39 -3
  22. package/dist/module/RealtimeClient.js.map +1 -1
  23. package/dist/module/RealtimePresence.d.ts +3 -3
  24. package/dist/module/RealtimePresence.d.ts.map +1 -1
  25. package/dist/module/RealtimePresence.js +2 -2
  26. package/dist/module/RealtimePresence.js.map +1 -1
  27. package/dist/module/lib/version.d.ts +1 -1
  28. package/dist/module/lib/version.js +1 -1
  29. package/package.json +3 -2
  30. package/src/RealtimeChannel.ts +232 -0
  31. package/src/RealtimeClient.ts +36 -3
  32. package/src/RealtimePresence.ts +4 -4
  33. package/src/lib/version.ts +1 -1
@@ -0,0 +1,232 @@
1
+ import { CHANNEL_EVENTS, CHANNEL_STATES } from './lib/constants'
2
+ import Push from './lib/push'
3
+ import RealtimeClient from './RealtimeClient'
4
+ import Timer from './lib/timer'
5
+ import RealtimePresence from './RealtimePresence'
6
+
7
+ export default class RealtimeChannel {
8
+ bindings: any[] = []
9
+ timeout: number
10
+ state = CHANNEL_STATES.closed
11
+ joinedOnce = false
12
+ joinPush: Push
13
+ rejoinTimer: Timer
14
+ pushBuffer: Push[] = []
15
+ presence: RealtimePresence
16
+
17
+ constructor(
18
+ public topic: string,
19
+ public params: { [key: string]: unknown } = {},
20
+ public socket: RealtimeClient
21
+ ) {
22
+ this.timeout = this.socket.timeout
23
+ this.joinPush = new Push(
24
+ this,
25
+ CHANNEL_EVENTS.join,
26
+ this.params,
27
+ this.timeout
28
+ )
29
+ this.rejoinTimer = new Timer(
30
+ () => this.rejoinUntilConnected(),
31
+ this.socket.reconnectAfterMs
32
+ )
33
+ this.joinPush.receive('ok', () => {
34
+ this.state = CHANNEL_STATES.joined
35
+ this.rejoinTimer.reset()
36
+ this.pushBuffer.forEach((pushEvent: Push) => pushEvent.send())
37
+ this.pushBuffer = []
38
+ })
39
+ this.onClose(() => {
40
+ this.rejoinTimer.reset()
41
+ this.socket.log('channel', `close ${this.topic} ${this.joinRef()}`)
42
+ this.state = CHANNEL_STATES.closed
43
+ this.socket.remove(this)
44
+ })
45
+ this.onError((reason: string) => {
46
+ if (this.isLeaving() || this.isClosed()) {
47
+ return
48
+ }
49
+ this.socket.log('channel', `error ${this.topic}`, reason)
50
+ this.state = CHANNEL_STATES.errored
51
+ this.rejoinTimer.scheduleTimeout()
52
+ })
53
+ this.joinPush.receive('timeout', () => {
54
+ if (!this.isJoining()) {
55
+ return
56
+ }
57
+ this.socket.log('channel', `timeout ${this.topic}`, this.joinPush.timeout)
58
+ this.state = CHANNEL_STATES.errored
59
+ this.rejoinTimer.scheduleTimeout()
60
+ })
61
+ this.on(CHANNEL_EVENTS.reply, {}, (payload: any, ref: string) => {
62
+ this.trigger(this.replyEventName(ref), payload)
63
+ })
64
+ this.presence = new RealtimePresence(this)
65
+ }
66
+
67
+ list() {
68
+ return this.presence.list()
69
+ }
70
+
71
+ rejoinUntilConnected() {
72
+ this.rejoinTimer.scheduleTimeout()
73
+ if (this.socket.isConnected()) {
74
+ this.rejoin()
75
+ }
76
+ }
77
+
78
+ subscribe(timeout = this.timeout) {
79
+ if (this.joinedOnce) {
80
+ throw `tried to subscribe multiple times. 'subscribe' can only be called a single time per channel instance`
81
+ } else {
82
+ this.joinedOnce = true
83
+ this.rejoin(timeout)
84
+ return this.joinPush
85
+ }
86
+ }
87
+
88
+ onClose(callback: Function) {
89
+ this.on(CHANNEL_EVENTS.close, {}, callback)
90
+ }
91
+
92
+ onError(callback: Function) {
93
+ this.on(CHANNEL_EVENTS.error, {}, (reason: string) => callback(reason))
94
+ }
95
+
96
+ on(type: string, eventFilter?: { [key: string]: any }, callback?: Function) {
97
+ this.bindings.push({ type, eventFilter: eventFilter ?? {}, callback })
98
+ }
99
+
100
+ off(event: string) {
101
+ this.bindings = this.bindings.filter((bind) => bind.event !== event)
102
+ }
103
+
104
+ canPush() {
105
+ return this.socket.isConnected() && this.isJoined()
106
+ }
107
+
108
+ push(event: CHANNEL_EVENTS, payload: any, timeout = this.timeout) {
109
+ if (!this.joinedOnce) {
110
+ throw `tried to push '${event}' to '${this.topic}' before joining. Use channel.subscribe() before pushing events`
111
+ }
112
+ let pushEvent = new Push(this, event, payload, timeout)
113
+ if (this.canPush()) {
114
+ pushEvent.send()
115
+ } else {
116
+ pushEvent.startTimeout()
117
+ this.pushBuffer.push(pushEvent)
118
+ }
119
+
120
+ return pushEvent
121
+ }
122
+
123
+ updateJoinPayload(payload: { [key: string]: unknown }): void {
124
+ this.joinPush.updatePayload(payload)
125
+ }
126
+
127
+ /**
128
+ * Leaves the channel
129
+ *
130
+ * Unsubscribes from server events, and instructs channel to terminate on server.
131
+ * Triggers onClose() hooks.
132
+ *
133
+ * To receive leave acknowledgements, use the a `receive` hook to bind to the server ack, ie:
134
+ * channel.unsubscribe().receive("ok", () => alert("left!") )
135
+ */
136
+ unsubscribe(timeout = this.timeout) {
137
+ this.state = CHANNEL_STATES.leaving
138
+ let onClose = () => {
139
+ this.socket.log('channel', `leave ${this.topic}`)
140
+ this.trigger(CHANNEL_EVENTS.close, 'leave', this.joinRef())
141
+ }
142
+ // Destroy joinPush to avoid connection timeouts during unscription phase
143
+ this.joinPush.destroy()
144
+
145
+ let leavePush = new Push(this, CHANNEL_EVENTS.leave, {}, timeout)
146
+ leavePush.receive('ok', () => onClose()).receive('timeout', () => onClose())
147
+ leavePush.send()
148
+ if (!this.canPush()) {
149
+ leavePush.trigger('ok', {})
150
+ }
151
+
152
+ return leavePush
153
+ }
154
+
155
+ /**
156
+ * Overridable message hook
157
+ *
158
+ * Receives all events for specialized message handling before dispatching to the channel callbacks.
159
+ * Must return the payload, modified or unmodified.
160
+ */
161
+ onMessage(event: string, payload: any, ref?: string) {
162
+ return payload
163
+ }
164
+
165
+ isMember(topic: string) {
166
+ return this.topic === topic
167
+ }
168
+
169
+ joinRef() {
170
+ return this.joinPush.ref
171
+ }
172
+
173
+ rejoin(timeout = this.timeout) {
174
+ if (this.isLeaving()) {
175
+ return
176
+ }
177
+ this.socket.leaveOpenTopic(this.topic)
178
+ this.state = CHANNEL_STATES.joining
179
+ this.joinPush.resend(timeout)
180
+ }
181
+
182
+ trigger(type: string, payload?: any, ref?: string) {
183
+ const { close, error, leave, join } = CHANNEL_EVENTS
184
+ const events: string[] = [close, error, leave, join]
185
+ if (ref && events.indexOf(type) >= 0 && ref !== this.joinRef()) {
186
+ return
187
+ }
188
+ const handledPayload = this.onMessage(type, payload, ref)
189
+ if (payload && !handledPayload) {
190
+ throw 'channel onMessage callbacks must return the payload, modified or unmodified'
191
+ }
192
+
193
+ this.bindings
194
+ .filter((bind) => {
195
+ return (
196
+ bind?.type === type &&
197
+ (bind?.eventFilter?.event === '*' ||
198
+ bind?.eventFilter?.event === payload?.event)
199
+ )
200
+ })
201
+ .map((bind) => bind.callback(handledPayload, ref))
202
+ }
203
+
204
+ send(payload: { type: string; [key: string]: any }) {
205
+ const push = this.push(payload.type as any, payload)
206
+
207
+ return new Promise((resolve) => {
208
+ push.receive('ok', () => resolve('ok'))
209
+ push.receive('timeout', () => resolve('timeout'))
210
+ })
211
+ }
212
+
213
+ replyEventName(ref: string) {
214
+ return `chan_reply_${ref}`
215
+ }
216
+
217
+ isClosed() {
218
+ return this.state === CHANNEL_STATES.closed
219
+ }
220
+ isErrored() {
221
+ return this.state === CHANNEL_STATES.errored
222
+ }
223
+ isJoined() {
224
+ return this.state === CHANNEL_STATES.joined
225
+ }
226
+ isJoining() {
227
+ return this.state === CHANNEL_STATES.joining
228
+ }
229
+ isLeaving() {
230
+ return this.state === CHANNEL_STATES.leaving
231
+ }
232
+ }
@@ -9,8 +9,9 @@ import {
9
9
  DEFAULT_HEADERS,
10
10
  } from './lib/constants'
11
11
  import Timer from './lib/timer'
12
- import RealtimeSubscription from './RealtimeSubscription'
13
12
  import Serializer from './lib/serializer'
13
+ import RealtimeSubscription from './RealtimeSubscription'
14
+ import RealtimeChannel from './RealtimeChannel'
14
15
 
15
16
  export type Options = {
16
17
  transport?: WebSocket
@@ -248,8 +249,40 @@ export default class RealtimeClient {
248
249
  )
249
250
  }
250
251
 
251
- channel(topic: string, chanParams = {}) {
252
- let chan = new RealtimeSubscription(topic, chanParams, this)
252
+ channel(
253
+ topic: string,
254
+ chanParams: { [key: string]: any } = { isNewVersion: false }
255
+ ) {
256
+ const { isNewVersion, ...params } = chanParams
257
+
258
+ const chan = isNewVersion
259
+ ? new RealtimeChannel(topic, { ...params }, this)
260
+ : new RealtimeSubscription(topic, { ...params }, this)
261
+
262
+ if (chan instanceof RealtimeChannel) {
263
+ chan.presence.onJoin((key, currentPresences, newPresences) => {
264
+ chan.trigger('presence', {
265
+ event: 'JOIN',
266
+ key,
267
+ currentPresences,
268
+ newPresences,
269
+ })
270
+ })
271
+
272
+ chan.presence.onLeave((key, currentPresences, leftPresences) => {
273
+ chan.trigger('presence', {
274
+ event: 'LEAVE',
275
+ key,
276
+ currentPresences,
277
+ leftPresences,
278
+ })
279
+ })
280
+
281
+ chan.presence.onSync(() => {
282
+ chan.trigger('presence', { event: 'SYNC' })
283
+ })
284
+ }
285
+
253
286
  this.channels.push(chan)
254
287
  return chan
255
288
  }
@@ -9,7 +9,7 @@ import {
9
9
  PresenceOnJoinCallback,
10
10
  PresenceOnLeaveCallback,
11
11
  } from 'phoenix'
12
- import RealtimeSubscription from './RealtimeSubscription'
12
+ import RealtimeChannel from './RealtimeChannel'
13
13
 
14
14
  type Presence = {
15
15
  presence_id: string
@@ -61,13 +61,13 @@ export default class RealtimePresence {
61
61
  * @param opts - The options,
62
62
  * for example `{events: {state: 'state', diff: 'diff'}}`
63
63
  */
64
- constructor(public channel: RealtimeSubscription, opts?: PresenceOpts) {
64
+ constructor(public channel: RealtimeChannel, opts?: PresenceOpts) {
65
65
  const events = opts?.events || {
66
66
  state: 'presence_state',
67
67
  diff: 'presence_diff',
68
68
  }
69
69
 
70
- this.channel.on(events.state, (newState: RawPresenceState) => {
70
+ this.channel.on(events.state, {}, (newState: RawPresenceState) => {
71
71
  const { onJoin, onLeave, onSync } = this.caller
72
72
 
73
73
  this.joinRef = this.channel.joinRef()
@@ -93,7 +93,7 @@ export default class RealtimePresence {
93
93
  onSync()
94
94
  })
95
95
 
96
- this.channel.on(events.diff, (diff: RawPresenceDiff) => {
96
+ this.channel.on(events.diff, {}, (diff: RawPresenceDiff) => {
97
97
  const { onJoin, onLeave, onSync } = this.caller
98
98
 
99
99
  if (this.inPendingSyncState()) {
@@ -1 +1 @@
1
- export const version = '1.4.3'
1
+ export const version = '1.4.6'