@supabase/realtime-js 2.99.3-canary.0 → 2.99.3
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 +28 -35
- package/dist/main/RealtimeChannel.d.ts.map +1 -1
- package/dist/main/RealtimeChannel.js +301 -140
- package/dist/main/RealtimeChannel.js.map +1 -1
- package/dist/main/RealtimeClient.d.ts +57 -38
- package/dist/main/RealtimeClient.d.ts.map +1 -1
- package/dist/main/RealtimeClient.js +520 -232
- package/dist/main/RealtimeClient.js.map +1 -1
- package/dist/main/RealtimePresence.d.ts +24 -8
- package/dist/main/RealtimePresence.d.ts.map +1 -1
- package/dist/main/RealtimePresence.js +202 -6
- package/dist/main/RealtimePresence.js.map +1 -1
- package/dist/main/lib/constants.d.ts +35 -39
- package/dist/main/lib/constants.d.ts.map +1 -1
- package/dist/main/lib/constants.js +35 -30
- package/dist/main/lib/constants.js.map +1 -1
- package/dist/main/lib/push.d.ts +48 -0
- package/dist/main/lib/push.d.ts.map +1 -0
- package/dist/main/lib/push.js +102 -0
- package/dist/main/lib/push.js.map +1 -0
- package/dist/main/lib/timer.d.ts +22 -0
- package/dist/main/lib/timer.d.ts.map +1 -0
- package/dist/main/lib/timer.js +39 -0
- package/dist/main/lib/timer.js.map +1 -0
- 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/main/lib/websocket-factory.d.ts +9 -0
- package/dist/main/lib/websocket-factory.d.ts.map +1 -1
- package/dist/main/lib/websocket-factory.js +12 -0
- package/dist/main/lib/websocket-factory.js.map +1 -1
- package/dist/module/RealtimeChannel.d.ts +28 -35
- package/dist/module/RealtimeChannel.d.ts.map +1 -1
- package/dist/module/RealtimeChannel.js +302 -141
- package/dist/module/RealtimeChannel.js.map +1 -1
- package/dist/module/RealtimeClient.d.ts +57 -38
- package/dist/module/RealtimeClient.d.ts.map +1 -1
- package/dist/module/RealtimeClient.js +521 -233
- package/dist/module/RealtimeClient.js.map +1 -1
- package/dist/module/RealtimePresence.d.ts +24 -8
- package/dist/module/RealtimePresence.d.ts.map +1 -1
- package/dist/module/RealtimePresence.js +202 -5
- package/dist/module/RealtimePresence.js.map +1 -1
- package/dist/module/lib/constants.d.ts +35 -39
- package/dist/module/lib/constants.d.ts.map +1 -1
- package/dist/module/lib/constants.js +35 -30
- package/dist/module/lib/constants.js.map +1 -1
- package/dist/module/lib/push.d.ts +48 -0
- package/dist/module/lib/push.d.ts.map +1 -0
- package/dist/module/lib/push.js +99 -0
- package/dist/module/lib/push.js.map +1 -0
- package/dist/module/lib/timer.d.ts +22 -0
- package/dist/module/lib/timer.d.ts.map +1 -0
- package/dist/module/lib/timer.js +36 -0
- package/dist/module/lib/timer.js.map +1 -0
- 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/module/lib/websocket-factory.d.ts +9 -0
- package/dist/module/lib/websocket-factory.d.ts.map +1 -1
- package/dist/module/lib/websocket-factory.js +12 -0
- package/dist/module/lib/websocket-factory.js.map +1 -1
- package/dist/tsconfig.module.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/RealtimeChannel.ts +364 -201
- package/src/RealtimeClient.ts +583 -296
- package/src/RealtimePresence.ts +287 -10
- package/src/lib/constants.ts +37 -50
- package/src/lib/push.ts +121 -0
- package/src/lib/timer.ts +43 -0
- package/src/lib/version.ts +1 -1
- package/src/lib/websocket-factory.ts +13 -0
- package/dist/main/phoenix/channelAdapter.d.ts +0 -32
- package/dist/main/phoenix/channelAdapter.d.ts.map +0 -1
- package/dist/main/phoenix/channelAdapter.js +0 -103
- package/dist/main/phoenix/channelAdapter.js.map +0 -1
- package/dist/main/phoenix/presenceAdapter.d.ts +0 -53
- package/dist/main/phoenix/presenceAdapter.d.ts.map +0 -1
- package/dist/main/phoenix/presenceAdapter.js +0 -93
- package/dist/main/phoenix/presenceAdapter.js.map +0 -1
- package/dist/main/phoenix/socketAdapter.d.ts +0 -38
- package/dist/main/phoenix/socketAdapter.d.ts.map +0 -1
- package/dist/main/phoenix/socketAdapter.js +0 -114
- package/dist/main/phoenix/socketAdapter.js.map +0 -1
- package/dist/main/phoenix/types.d.ts +0 -5
- package/dist/main/phoenix/types.d.ts.map +0 -1
- package/dist/main/phoenix/types.js +0 -3
- package/dist/main/phoenix/types.js.map +0 -1
- package/dist/module/phoenix/channelAdapter.d.ts +0 -32
- package/dist/module/phoenix/channelAdapter.d.ts.map +0 -1
- package/dist/module/phoenix/channelAdapter.js +0 -100
- package/dist/module/phoenix/channelAdapter.js.map +0 -1
- package/dist/module/phoenix/presenceAdapter.d.ts +0 -53
- package/dist/module/phoenix/presenceAdapter.d.ts.map +0 -1
- package/dist/module/phoenix/presenceAdapter.js +0 -90
- package/dist/module/phoenix/presenceAdapter.js.map +0 -1
- package/dist/module/phoenix/socketAdapter.d.ts +0 -38
- package/dist/module/phoenix/socketAdapter.d.ts.map +0 -1
- package/dist/module/phoenix/socketAdapter.js +0 -111
- package/dist/module/phoenix/socketAdapter.js.map +0 -1
- package/dist/module/phoenix/types.d.ts +0 -5
- package/dist/module/phoenix/types.d.ts.map +0 -1
- package/dist/module/phoenix/types.js +0 -2
- package/dist/module/phoenix/types.js.map +0 -1
- package/src/phoenix/channelAdapter.ts +0 -147
- package/src/phoenix/presenceAdapter.ts +0 -116
- package/src/phoenix/socketAdapter.ts +0 -168
- package/src/phoenix/types.ts +0 -32
package/src/RealtimePresence.ts
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
License: https://github.com/phoenixframework/phoenix/blob/d344ec0a732ab4ee204215b31de69cf4be72e3bf/LICENSE.md
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import type { PresenceOpts, PresenceOnJoinCallback, PresenceOnLeaveCallback } from 'phoenix'
|
|
6
7
|
import type RealtimeChannel from './RealtimeChannel'
|
|
7
|
-
import PresenceAdapter from './phoenix/presenceAdapter'
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
type Presence<T extends { [key: string]: any } = {}> = {
|
|
10
10
|
presence_ref: string
|
|
11
11
|
} & T
|
|
12
12
|
|
|
@@ -34,16 +34,42 @@ export enum REALTIME_PRESENCE_LISTEN_EVENTS {
|
|
|
34
34
|
LEAVE = 'leave',
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
type PresenceDiff = {
|
|
38
|
+
joins: RealtimePresenceState
|
|
39
|
+
leaves: RealtimePresenceState
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
type RawPresenceState = {
|
|
43
|
+
[key: string]: {
|
|
44
|
+
metas: {
|
|
45
|
+
phx_ref?: string
|
|
46
|
+
phx_ref_prev?: string
|
|
47
|
+
[key: string]: any
|
|
48
|
+
}[]
|
|
44
49
|
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type RawPresenceDiff = {
|
|
53
|
+
joins: RawPresenceState
|
|
54
|
+
leaves: RawPresenceState
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type PresenceChooser<T> = (key: string, presences: Presence[]) => T
|
|
45
58
|
|
|
46
|
-
|
|
59
|
+
export default class RealtimePresence {
|
|
60
|
+
state: RealtimePresenceState = {}
|
|
61
|
+
pendingDiffs: RawPresenceDiff[] = []
|
|
62
|
+
joinRef: string | null = null
|
|
63
|
+
enabled: boolean = false
|
|
64
|
+
caller: {
|
|
65
|
+
onJoin: PresenceOnJoinCallback
|
|
66
|
+
onLeave: PresenceOnLeaveCallback
|
|
67
|
+
onSync: () => void
|
|
68
|
+
} = {
|
|
69
|
+
onJoin: () => {},
|
|
70
|
+
onLeave: () => {},
|
|
71
|
+
onSync: () => {},
|
|
72
|
+
}
|
|
47
73
|
|
|
48
74
|
/**
|
|
49
75
|
* Creates a Presence helper that keeps the local presence state in sync with the server.
|
|
@@ -62,8 +88,259 @@ export default class RealtimePresence {
|
|
|
62
88
|
*/
|
|
63
89
|
constructor(
|
|
64
90
|
public channel: RealtimeChannel,
|
|
65
|
-
opts?:
|
|
91
|
+
opts?: PresenceOpts
|
|
66
92
|
) {
|
|
67
|
-
|
|
93
|
+
const events = opts?.events || {
|
|
94
|
+
state: 'presence_state',
|
|
95
|
+
diff: 'presence_diff',
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.channel._on(events.state, {}, (newState: RawPresenceState) => {
|
|
99
|
+
const { onJoin, onLeave, onSync } = this.caller
|
|
100
|
+
|
|
101
|
+
this.joinRef = this.channel._joinRef()
|
|
102
|
+
|
|
103
|
+
this.state = RealtimePresence.syncState(this.state, newState, onJoin, onLeave)
|
|
104
|
+
|
|
105
|
+
this.pendingDiffs.forEach((diff) => {
|
|
106
|
+
this.state = RealtimePresence.syncDiff(this.state, diff, onJoin, onLeave)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
this.pendingDiffs = []
|
|
110
|
+
|
|
111
|
+
onSync()
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
this.channel._on(events.diff, {}, (diff: RawPresenceDiff) => {
|
|
115
|
+
const { onJoin, onLeave, onSync } = this.caller
|
|
116
|
+
|
|
117
|
+
if (this.inPendingSyncState()) {
|
|
118
|
+
this.pendingDiffs.push(diff)
|
|
119
|
+
} else {
|
|
120
|
+
this.state = RealtimePresence.syncDiff(this.state, diff, onJoin, onLeave)
|
|
121
|
+
|
|
122
|
+
onSync()
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
this.onJoin((key, currentPresences, newPresences) => {
|
|
127
|
+
this.channel._trigger('presence', {
|
|
128
|
+
event: 'join',
|
|
129
|
+
key,
|
|
130
|
+
currentPresences,
|
|
131
|
+
newPresences,
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
this.onLeave((key, currentPresences, leftPresences) => {
|
|
136
|
+
this.channel._trigger('presence', {
|
|
137
|
+
event: 'leave',
|
|
138
|
+
key,
|
|
139
|
+
currentPresences,
|
|
140
|
+
leftPresences,
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
this.onSync(() => {
|
|
145
|
+
this.channel._trigger('presence', { event: 'sync' })
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Used to sync the list of presences on the server with the
|
|
151
|
+
* client's state.
|
|
152
|
+
*
|
|
153
|
+
* An optional `onJoin` and `onLeave` callback can be provided to
|
|
154
|
+
* react to changes in the client's local presences across
|
|
155
|
+
* disconnects and reconnects with the server.
|
|
156
|
+
*
|
|
157
|
+
* @internal
|
|
158
|
+
*/
|
|
159
|
+
private static syncState(
|
|
160
|
+
currentState: RealtimePresenceState,
|
|
161
|
+
newState: RawPresenceState | RealtimePresenceState,
|
|
162
|
+
onJoin: PresenceOnJoinCallback,
|
|
163
|
+
onLeave: PresenceOnLeaveCallback
|
|
164
|
+
): RealtimePresenceState {
|
|
165
|
+
const state = this.cloneDeep(currentState)
|
|
166
|
+
const transformedState = this.transformState(newState)
|
|
167
|
+
const joins: RealtimePresenceState = {}
|
|
168
|
+
const leaves: RealtimePresenceState = {}
|
|
169
|
+
|
|
170
|
+
this.map(state, (key: string, presences: Presence[]) => {
|
|
171
|
+
if (!transformedState[key]) {
|
|
172
|
+
leaves[key] = presences
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
this.map(transformedState, (key, newPresences: Presence[]) => {
|
|
177
|
+
const currentPresences: Presence[] = state[key]
|
|
178
|
+
|
|
179
|
+
if (currentPresences) {
|
|
180
|
+
const newPresenceRefs = newPresences.map((m: Presence) => m.presence_ref)
|
|
181
|
+
const curPresenceRefs = currentPresences.map((m: Presence) => m.presence_ref)
|
|
182
|
+
const joinedPresences: Presence[] = newPresences.filter(
|
|
183
|
+
(m: Presence) => curPresenceRefs.indexOf(m.presence_ref) < 0
|
|
184
|
+
)
|
|
185
|
+
const leftPresences: Presence[] = currentPresences.filter(
|
|
186
|
+
(m: Presence) => newPresenceRefs.indexOf(m.presence_ref) < 0
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if (joinedPresences.length > 0) {
|
|
190
|
+
joins[key] = joinedPresences
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (leftPresences.length > 0) {
|
|
194
|
+
leaves[key] = leftPresences
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
joins[key] = newPresences
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
return this.syncDiff(state, { joins, leaves }, onJoin, onLeave)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Used to sync a diff of presence join and leave events from the
|
|
206
|
+
* server, as they happen.
|
|
207
|
+
*
|
|
208
|
+
* Like `syncState`, `syncDiff` accepts optional `onJoin` and
|
|
209
|
+
* `onLeave` callbacks to react to a user joining or leaving from a
|
|
210
|
+
* device.
|
|
211
|
+
*
|
|
212
|
+
* @internal
|
|
213
|
+
*/
|
|
214
|
+
private static syncDiff(
|
|
215
|
+
state: RealtimePresenceState,
|
|
216
|
+
diff: RawPresenceDiff | PresenceDiff,
|
|
217
|
+
onJoin: PresenceOnJoinCallback,
|
|
218
|
+
onLeave: PresenceOnLeaveCallback
|
|
219
|
+
): RealtimePresenceState {
|
|
220
|
+
const { joins, leaves } = {
|
|
221
|
+
joins: this.transformState(diff.joins),
|
|
222
|
+
leaves: this.transformState(diff.leaves),
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!onJoin) {
|
|
226
|
+
onJoin = () => {}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!onLeave) {
|
|
230
|
+
onLeave = () => {}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.map(joins, (key, newPresences: Presence[]) => {
|
|
234
|
+
const currentPresences: Presence[] = state[key] ?? []
|
|
235
|
+
state[key] = this.cloneDeep(newPresences)
|
|
236
|
+
|
|
237
|
+
if (currentPresences.length > 0) {
|
|
238
|
+
const joinedPresenceRefs = state[key].map((m: Presence) => m.presence_ref)
|
|
239
|
+
const curPresences: Presence[] = currentPresences.filter(
|
|
240
|
+
(m: Presence) => joinedPresenceRefs.indexOf(m.presence_ref) < 0
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
state[key].unshift(...curPresences)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
onJoin(key, currentPresences, newPresences)
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
this.map(leaves, (key, leftPresences: Presence[]) => {
|
|
250
|
+
let currentPresences: Presence[] = state[key]
|
|
251
|
+
|
|
252
|
+
if (!currentPresences) return
|
|
253
|
+
|
|
254
|
+
const presenceRefsToRemove = leftPresences.map((m: Presence) => m.presence_ref)
|
|
255
|
+
currentPresences = currentPresences.filter(
|
|
256
|
+
(m: Presence) => presenceRefsToRemove.indexOf(m.presence_ref) < 0
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
state[key] = currentPresences
|
|
260
|
+
|
|
261
|
+
onLeave(key, currentPresences, leftPresences)
|
|
262
|
+
|
|
263
|
+
if (currentPresences.length === 0) delete state[key]
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
return state
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** @internal */
|
|
270
|
+
private static map<T = any>(obj: RealtimePresenceState, func: PresenceChooser<T>): T[] {
|
|
271
|
+
return Object.getOwnPropertyNames(obj).map((key) => func(key, obj[key]))
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Remove 'metas' key
|
|
276
|
+
* Change 'phx_ref' to 'presence_ref'
|
|
277
|
+
* Remove 'phx_ref' and 'phx_ref_prev'
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* // returns {
|
|
281
|
+
* abc123: [
|
|
282
|
+
* { presence_ref: '2', user_id: 1 },
|
|
283
|
+
* { presence_ref: '3', user_id: 2 }
|
|
284
|
+
* ]
|
|
285
|
+
* }
|
|
286
|
+
* RealtimePresence.transformState({
|
|
287
|
+
* abc123: {
|
|
288
|
+
* metas: [
|
|
289
|
+
* { phx_ref: '2', phx_ref_prev: '1' user_id: 1 },
|
|
290
|
+
* { phx_ref: '3', user_id: 2 }
|
|
291
|
+
* ]
|
|
292
|
+
* }
|
|
293
|
+
* })
|
|
294
|
+
*
|
|
295
|
+
* @internal
|
|
296
|
+
*/
|
|
297
|
+
private static transformState(
|
|
298
|
+
state: RawPresenceState | RealtimePresenceState
|
|
299
|
+
): RealtimePresenceState {
|
|
300
|
+
state = this.cloneDeep(state)
|
|
301
|
+
|
|
302
|
+
return Object.getOwnPropertyNames(state).reduce((newState, key) => {
|
|
303
|
+
const presences = state[key]
|
|
304
|
+
|
|
305
|
+
if ('metas' in presences) {
|
|
306
|
+
newState[key] = presences.metas.map((presence) => {
|
|
307
|
+
presence['presence_ref'] = presence['phx_ref']
|
|
308
|
+
|
|
309
|
+
delete presence['phx_ref']
|
|
310
|
+
delete presence['phx_ref_prev']
|
|
311
|
+
|
|
312
|
+
return presence
|
|
313
|
+
}) as Presence[]
|
|
314
|
+
} else {
|
|
315
|
+
newState[key] = presences
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return newState
|
|
319
|
+
}, {} as RealtimePresenceState)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** @internal */
|
|
323
|
+
private static cloneDeep(obj: { [key: string]: any }) {
|
|
324
|
+
return JSON.parse(JSON.stringify(obj))
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** @internal */
|
|
328
|
+
private onJoin(callback: PresenceOnJoinCallback): void {
|
|
329
|
+
this.caller.onJoin = callback
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** @internal */
|
|
333
|
+
private onLeave(callback: PresenceOnLeaveCallback): void {
|
|
334
|
+
this.caller.onLeave = callback
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** @internal */
|
|
338
|
+
private onSync(callback: () => void): void {
|
|
339
|
+
this.caller.onSync = callback
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** @internal */
|
|
343
|
+
private inPendingSyncState(): boolean {
|
|
344
|
+
return !this.joinRef || this.joinRef !== this.channel._joinRef()
|
|
68
345
|
}
|
|
69
346
|
}
|
package/src/lib/constants.ts
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
import { version } from './version'
|
|
2
|
-
import type {
|
|
3
|
-
SocketState,
|
|
4
|
-
ChannelState,
|
|
5
|
-
ChannelEvent as PhoenixChannelEvent,
|
|
6
|
-
Transport,
|
|
7
|
-
Vsn,
|
|
8
|
-
} from '../phoenix/types'
|
|
9
|
-
|
|
10
|
-
export type { SocketState, ChannelState, Transport }
|
|
11
2
|
|
|
12
3
|
export const DEFAULT_VERSION = `realtime-js/${version}`
|
|
13
4
|
|
|
14
|
-
export const VSN_1_0_0:
|
|
15
|
-
export const VSN_2_0_0:
|
|
16
|
-
export const DEFAULT_VSN:
|
|
5
|
+
export const VSN_1_0_0: string = '1.0.0'
|
|
6
|
+
export const VSN_2_0_0: string = '2.0.0'
|
|
7
|
+
export const DEFAULT_VSN: string = VSN_2_0_0
|
|
17
8
|
|
|
18
9
|
export const VERSION = version
|
|
19
10
|
|
|
@@ -22,41 +13,37 @@ export const DEFAULT_TIMEOUT = 10000
|
|
|
22
13
|
export const WS_CLOSE_NORMAL = 1000
|
|
23
14
|
export const MAX_PUSH_BUFFER_SIZE = 100
|
|
24
15
|
|
|
25
|
-
export
|
|
26
|
-
connecting
|
|
27
|
-
open
|
|
28
|
-
closing
|
|
29
|
-
closed
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export
|
|
33
|
-
closed
|
|
34
|
-
errored
|
|
35
|
-
joined
|
|
36
|
-
joining
|
|
37
|
-
leaving
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
open: 'open',
|
|
60
|
-
closing: 'closing',
|
|
61
|
-
closed: 'closed',
|
|
62
|
-
} as const
|
|
16
|
+
export enum SOCKET_STATES {
|
|
17
|
+
connecting = 0,
|
|
18
|
+
open = 1,
|
|
19
|
+
closing = 2,
|
|
20
|
+
closed = 3,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export enum CHANNEL_STATES {
|
|
24
|
+
closed = 'closed',
|
|
25
|
+
errored = 'errored',
|
|
26
|
+
joined = 'joined',
|
|
27
|
+
joining = 'joining',
|
|
28
|
+
leaving = 'leaving',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export enum CHANNEL_EVENTS {
|
|
32
|
+
close = 'phx_close',
|
|
33
|
+
error = 'phx_error',
|
|
34
|
+
join = 'phx_join',
|
|
35
|
+
reply = 'phx_reply',
|
|
36
|
+
leave = 'phx_leave',
|
|
37
|
+
access_token = 'access_token',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export enum TRANSPORTS {
|
|
41
|
+
websocket = 'websocket',
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export enum CONNECTION_STATE {
|
|
45
|
+
Connecting = 'connecting',
|
|
46
|
+
Open = 'open',
|
|
47
|
+
Closing = 'closing',
|
|
48
|
+
Closed = 'closed',
|
|
49
|
+
}
|
package/src/lib/push.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { DEFAULT_TIMEOUT } from '../lib/constants'
|
|
2
|
+
import type RealtimeChannel from '../RealtimeChannel'
|
|
3
|
+
|
|
4
|
+
export default class Push {
|
|
5
|
+
sent: boolean = false
|
|
6
|
+
timeoutTimer: number | undefined = undefined
|
|
7
|
+
ref: string = ''
|
|
8
|
+
receivedResp: {
|
|
9
|
+
status: string
|
|
10
|
+
response: { [key: string]: any }
|
|
11
|
+
} | null = null
|
|
12
|
+
recHooks: {
|
|
13
|
+
status: string
|
|
14
|
+
callback: Function
|
|
15
|
+
}[] = []
|
|
16
|
+
refEvent: string | null = null
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Initializes the Push
|
|
20
|
+
*
|
|
21
|
+
* @param channel The Channel
|
|
22
|
+
* @param event The event, for example `"phx_join"`
|
|
23
|
+
* @param payload The payload, for example `{user_id: 123}`
|
|
24
|
+
* @param timeout The push timeout in milliseconds
|
|
25
|
+
*/
|
|
26
|
+
constructor(
|
|
27
|
+
public channel: RealtimeChannel,
|
|
28
|
+
public event: string,
|
|
29
|
+
public payload: { [key: string]: any } = {},
|
|
30
|
+
public timeout: number = DEFAULT_TIMEOUT
|
|
31
|
+
) {}
|
|
32
|
+
|
|
33
|
+
resend(timeout: number) {
|
|
34
|
+
this.timeout = timeout
|
|
35
|
+
this._cancelRefEvent()
|
|
36
|
+
this.ref = ''
|
|
37
|
+
this.refEvent = null
|
|
38
|
+
this.receivedResp = null
|
|
39
|
+
this.sent = false
|
|
40
|
+
this.send()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
send() {
|
|
44
|
+
if (this._hasReceived('timeout')) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
this.startTimeout()
|
|
48
|
+
this.sent = true
|
|
49
|
+
this.channel.socket.push({
|
|
50
|
+
topic: this.channel.topic,
|
|
51
|
+
event: this.event,
|
|
52
|
+
payload: this.payload,
|
|
53
|
+
ref: this.ref,
|
|
54
|
+
join_ref: this.channel._joinRef(),
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
updatePayload(payload: { [key: string]: any }): void {
|
|
59
|
+
this.payload = { ...this.payload, ...payload }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
receive(status: string, callback: Function) {
|
|
63
|
+
if (this._hasReceived(status)) {
|
|
64
|
+
callback(this.receivedResp?.response)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.recHooks.push({ status, callback })
|
|
68
|
+
return this
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
startTimeout() {
|
|
72
|
+
if (this.timeoutTimer) {
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
this.ref = this.channel.socket._makeRef()
|
|
76
|
+
this.refEvent = this.channel._replyEventName(this.ref)
|
|
77
|
+
|
|
78
|
+
const callback = (payload: any) => {
|
|
79
|
+
this._cancelRefEvent()
|
|
80
|
+
this._cancelTimeout()
|
|
81
|
+
this.receivedResp = payload
|
|
82
|
+
this._matchReceive(payload)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.channel._on(this.refEvent, {}, callback)
|
|
86
|
+
|
|
87
|
+
this.timeoutTimer = <any>setTimeout(() => {
|
|
88
|
+
this.trigger('timeout', {})
|
|
89
|
+
}, this.timeout)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
trigger(status: string, response: any) {
|
|
93
|
+
if (this.refEvent) this.channel._trigger(this.refEvent, { status, response })
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
destroy() {
|
|
97
|
+
this._cancelRefEvent()
|
|
98
|
+
this._cancelTimeout()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private _cancelRefEvent() {
|
|
102
|
+
if (!this.refEvent) {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.channel._off(this.refEvent, {})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private _cancelTimeout() {
|
|
110
|
+
clearTimeout(this.timeoutTimer)
|
|
111
|
+
this.timeoutTimer = undefined
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private _matchReceive({ status, response }: { status: string; response: Function }) {
|
|
115
|
+
this.recHooks.filter((h) => h.status === status).forEach((h) => h.callback(response))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private _hasReceived(status: string) {
|
|
119
|
+
return this.receivedResp && this.receivedResp.status === status
|
|
120
|
+
}
|
|
121
|
+
}
|
package/src/lib/timer.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a timer that accepts a `timerCalc` function to perform calculated timeout retries, such as exponential backoff.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* let reconnectTimer = new Timer(() => this.connect(), function(tries){
|
|
6
|
+
* return [1000, 5000, 10000][tries - 1] || 10000
|
|
7
|
+
* })
|
|
8
|
+
* reconnectTimer.scheduleTimeout() // fires after 1000
|
|
9
|
+
* reconnectTimer.scheduleTimeout() // fires after 5000
|
|
10
|
+
* reconnectTimer.reset()
|
|
11
|
+
* reconnectTimer.scheduleTimeout() // fires after 1000
|
|
12
|
+
*/
|
|
13
|
+
export default class Timer {
|
|
14
|
+
timer: number | undefined = undefined
|
|
15
|
+
tries: number = 0
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
public callback: Function,
|
|
19
|
+
public timerCalc: Function
|
|
20
|
+
) {
|
|
21
|
+
this.callback = callback
|
|
22
|
+
this.timerCalc = timerCalc
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
reset() {
|
|
26
|
+
this.tries = 0
|
|
27
|
+
clearTimeout(this.timer)
|
|
28
|
+
this.timer = undefined
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Cancels any previous scheduleTimeout and schedules callback
|
|
32
|
+
scheduleTimeout() {
|
|
33
|
+
clearTimeout(this.timer)
|
|
34
|
+
|
|
35
|
+
this.timer = <any>setTimeout(
|
|
36
|
+
() => {
|
|
37
|
+
this.tries = this.tries + 1
|
|
38
|
+
this.callback()
|
|
39
|
+
},
|
|
40
|
+
this.timerCalc(this.tries + 1)
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
}
|
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.99.3
|
|
7
|
+
export const version = '2.99.3'
|
|
@@ -156,6 +156,19 @@ export class WebSocketFactory {
|
|
|
156
156
|
throw new Error(errorMessage)
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Creates a WebSocket using the detected constructor.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* const socket = WebSocketFactory.createWebSocket('wss://realtime.supabase.co/socket')
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
public static createWebSocket(url: string | URL, protocols?: string | string[]): WebSocketLike {
|
|
168
|
+
const WS = this.getWebSocketConstructor()
|
|
169
|
+
return new WS(url, protocols)
|
|
170
|
+
}
|
|
171
|
+
|
|
159
172
|
/**
|
|
160
173
|
* Detects whether the runtime can establish WebSocket connections.
|
|
161
174
|
*
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { RealtimeChannelOptions } from '../RealtimeChannel';
|
|
2
|
-
import SocketAdapter from './socketAdapter';
|
|
3
|
-
import type { ChannelBindingCallback, ChannelOnMessage, ChannelOnErrorCallback, ChannelFilterBindings, ChannelState, Push, Timer } from './types';
|
|
4
|
-
export default class ChannelAdapter {
|
|
5
|
-
private channel;
|
|
6
|
-
private socket;
|
|
7
|
-
constructor(socket: SocketAdapter, topic: string, params: RealtimeChannelOptions);
|
|
8
|
-
get state(): ChannelState;
|
|
9
|
-
set state(state: ChannelState);
|
|
10
|
-
get joinedOnce(): boolean;
|
|
11
|
-
get joinPush(): Push;
|
|
12
|
-
get rejoinTimer(): Timer;
|
|
13
|
-
on(event: string, callback: ChannelBindingCallback): number;
|
|
14
|
-
off(event: string, refNumber?: number): void;
|
|
15
|
-
subscribe(timeout?: number): Push;
|
|
16
|
-
unsubscribe(timeout?: number): Push;
|
|
17
|
-
teardown(): void;
|
|
18
|
-
onClose(callback: ChannelBindingCallback): void;
|
|
19
|
-
onError(callback: ChannelOnErrorCallback): number;
|
|
20
|
-
push(event: string, payload: {
|
|
21
|
-
[key: string]: any;
|
|
22
|
-
}, timeout?: number): Push;
|
|
23
|
-
updateJoinPayload(payload: Record<string, any>): void;
|
|
24
|
-
canPush(): boolean;
|
|
25
|
-
isJoined(): boolean;
|
|
26
|
-
isJoining(): boolean;
|
|
27
|
-
isClosed(): boolean;
|
|
28
|
-
isLeaving(): boolean;
|
|
29
|
-
updateFilterBindings(filterBindings: ChannelFilterBindings): void;
|
|
30
|
-
updatePayloadTransform(callback: ChannelOnMessage): void;
|
|
31
|
-
}
|
|
32
|
-
//# sourceMappingURL=channelAdapter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"channelAdapter.d.ts","sourceRoot":"","sources":["../../../src/phoenix/channelAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAChE,OAAO,aAAa,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EAErB,YAAY,EACZ,IAAI,EACJ,KAAK,EACN,MAAM,SAAS,CAAA;AAEhB,MAAM,CAAC,OAAO,OAAO,cAAc;IACjC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB;IAMhF,IAAI,KAAK,IAAI,YAAY,CAExB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,YAAY,EAE5B;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,QAAQ,IAAI,IAAI,CAEnB;IAED,IAAI,WAAW,IAAI,KAAK,CAEvB;IAED,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,MAAM;IAI3D,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAIrC,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAIjC,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAInC,QAAQ;IAIR,OAAO,CAAC,QAAQ,EAAE,sBAAsB;IAIxC,OAAO,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM;IAIjD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAqB5E,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAK9C,OAAO;IAIP,QAAQ;IAIR,SAAS;IAIT,QAAQ;IAIR,SAAS;IAIT,oBAAoB,CAAC,cAAc,EAAE,qBAAqB;IAI1D,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB;CAUlD"}
|