@depup/supabase__realtime-js 2.99.3-depup.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 +32 -0
- package/changes.json +14 -0
- package/dist/main/RealtimeChannel.d.ts +370 -0
- package/dist/main/RealtimeChannel.d.ts.map +1 -0
- package/dist/main/RealtimeChannel.js +644 -0
- package/dist/main/RealtimeChannel.js.map +1 -0
- package/dist/main/RealtimeClient.d.ts +238 -0
- package/dist/main/RealtimeClient.d.ts.map +1 -0
- package/dist/main/RealtimeClient.js +870 -0
- package/dist/main/RealtimeClient.js.map +1 -0
- package/dist/main/RealtimePresence.d.ts +76 -0
- package/dist/main/RealtimePresence.d.ts.map +1 -0
- package/dist/main/RealtimePresence.js +237 -0
- package/dist/main/RealtimePresence.js.map +1 -0
- package/dist/main/index.d.ts +6 -0
- package/dist/main/index.d.ts.map +1 -0
- package/dist/main/index.js +18 -0
- package/dist/main/index.js.map +1 -0
- package/dist/main/lib/constants.d.ts +39 -0
- package/dist/main/lib/constants.d.ts.map +1 -0
- package/dist/main/lib/constants.js +48 -0
- package/dist/main/lib/constants.js.map +1 -0
- 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/serializer.d.ts +33 -0
- package/dist/main/lib/serializer.d.ts.map +1 -0
- package/dist/main/lib/serializer.js +155 -0
- package/dist/main/lib/serializer.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/transformers.d.ts +109 -0
- package/dist/main/lib/transformers.d.ts.map +1 -0
- package/dist/main/lib/transformers.js +241 -0
- package/dist/main/lib/transformers.js.map +1 -0
- package/dist/main/lib/version.d.ts +2 -0
- package/dist/main/lib/version.d.ts.map +1 -0
- package/dist/main/lib/version.js +11 -0
- package/dist/main/lib/version.js.map +1 -0
- package/dist/main/lib/websocket-factory.d.ts +81 -0
- package/dist/main/lib/websocket-factory.d.ts.map +1 -0
- package/dist/main/lib/websocket-factory.js +131 -0
- package/dist/main/lib/websocket-factory.js.map +1 -0
- package/dist/module/RealtimeChannel.d.ts +370 -0
- package/dist/module/RealtimeChannel.d.ts.map +1 -0
- package/dist/module/RealtimeChannel.js +639 -0
- package/dist/module/RealtimeChannel.js.map +1 -0
- package/dist/module/RealtimeClient.d.ts +238 -0
- package/dist/module/RealtimeClient.d.ts.map +1 -0
- package/dist/module/RealtimeClient.js +866 -0
- package/dist/module/RealtimeClient.js.map +1 -0
- package/dist/module/RealtimePresence.d.ts +76 -0
- package/dist/module/RealtimePresence.d.ts.map +1 -0
- package/dist/module/RealtimePresence.js +233 -0
- package/dist/module/RealtimePresence.js.map +1 -0
- package/dist/module/index.d.ts +6 -0
- package/dist/module/index.d.ts.map +1 -0
- package/dist/module/index.js +6 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/lib/constants.d.ts +39 -0
- package/dist/module/lib/constants.d.ts.map +1 -0
- package/dist/module/lib/constants.js +45 -0
- package/dist/module/lib/constants.js.map +1 -0
- 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/serializer.d.ts +33 -0
- package/dist/module/lib/serializer.d.ts.map +1 -0
- package/dist/module/lib/serializer.js +152 -0
- package/dist/module/lib/serializer.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/transformers.d.ts +109 -0
- package/dist/module/lib/transformers.d.ts.map +1 -0
- package/dist/module/lib/transformers.js +229 -0
- package/dist/module/lib/transformers.js.map +1 -0
- package/dist/module/lib/version.d.ts +2 -0
- package/dist/module/lib/version.d.ts.map +1 -0
- package/dist/module/lib/version.js +8 -0
- package/dist/module/lib/version.js.map +1 -0
- package/dist/module/lib/websocket-factory.d.ts +81 -0
- package/dist/module/lib/websocket-factory.d.ts.map +1 -0
- package/dist/module/lib/websocket-factory.js +127 -0
- package/dist/module/lib/websocket-factory.js.map +1 -0
- package/dist/tsconfig.module.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +85 -0
- package/src/RealtimeChannel.ts +1039 -0
- package/src/RealtimeClient.ts +1023 -0
- package/src/RealtimePresence.ts +346 -0
- package/src/index.ts +53 -0
- package/src/lib/constants.ts +49 -0
- package/src/lib/push.ts +121 -0
- package/src/lib/serializer.ts +203 -0
- package/src/lib/timer.ts +43 -0
- package/src/lib/transformers.ts +270 -0
- package/src/lib/version.ts +7 -0
- package/src/lib/websocket-factory.ts +192 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This file draws heavily from https://github.com/phoenixframework/phoenix/blob/d344ec0a732ab4ee204215b31de69cf4be72e3bf/assets/js/phoenix/presence.js
|
|
3
|
+
License: https://github.com/phoenixframework/phoenix/blob/d344ec0a732ab4ee204215b31de69cf4be72e3bf/LICENSE.md
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { PresenceOpts, PresenceOnJoinCallback, PresenceOnLeaveCallback } from 'phoenix'
|
|
7
|
+
import type RealtimeChannel from './RealtimeChannel'
|
|
8
|
+
|
|
9
|
+
type Presence<T extends { [key: string]: any } = {}> = {
|
|
10
|
+
presence_ref: string
|
|
11
|
+
} & T
|
|
12
|
+
|
|
13
|
+
export type RealtimePresenceState<T extends { [key: string]: any } = {}> = {
|
|
14
|
+
[key: string]: Presence<T>[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type RealtimePresenceJoinPayload<T extends { [key: string]: any }> = {
|
|
18
|
+
event: `${REALTIME_PRESENCE_LISTEN_EVENTS.JOIN}`
|
|
19
|
+
key: string
|
|
20
|
+
currentPresences: Presence<T>[]
|
|
21
|
+
newPresences: Presence<T>[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type RealtimePresenceLeavePayload<T extends { [key: string]: any }> = {
|
|
25
|
+
event: `${REALTIME_PRESENCE_LISTEN_EVENTS.LEAVE}`
|
|
26
|
+
key: string
|
|
27
|
+
currentPresences: Presence<T>[]
|
|
28
|
+
leftPresences: Presence<T>[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export enum REALTIME_PRESENCE_LISTEN_EVENTS {
|
|
32
|
+
SYNC = 'sync',
|
|
33
|
+
JOIN = 'join',
|
|
34
|
+
LEAVE = 'leave',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type PresenceDiff = {
|
|
38
|
+
joins: RealtimePresenceState
|
|
39
|
+
leaves: RealtimePresenceState
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type RawPresenceState = {
|
|
43
|
+
[key: string]: {
|
|
44
|
+
metas: {
|
|
45
|
+
phx_ref?: string
|
|
46
|
+
phx_ref_prev?: string
|
|
47
|
+
[key: string]: any
|
|
48
|
+
}[]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type RawPresenceDiff = {
|
|
53
|
+
joins: RawPresenceState
|
|
54
|
+
leaves: RawPresenceState
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type PresenceChooser<T> = (key: string, presences: Presence[]) => T
|
|
58
|
+
|
|
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
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates a Presence helper that keeps the local presence state in sync with the server.
|
|
76
|
+
*
|
|
77
|
+
* @param channel - The realtime channel to bind to.
|
|
78
|
+
* @param opts - Optional custom event names, e.g. `{ events: { state: 'state', diff: 'diff' } }`.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const presence = new RealtimePresence(channel)
|
|
83
|
+
*
|
|
84
|
+
* channel.on('presence', ({ event, key }) => {
|
|
85
|
+
* console.log(`Presence ${event} on ${key}`)
|
|
86
|
+
* })
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
constructor(
|
|
90
|
+
public channel: RealtimeChannel,
|
|
91
|
+
opts?: PresenceOpts
|
|
92
|
+
) {
|
|
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()
|
|
345
|
+
}
|
|
346
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import RealtimeClient, {
|
|
2
|
+
RealtimeClientOptions,
|
|
3
|
+
RealtimeMessage,
|
|
4
|
+
RealtimeRemoveChannelResponse,
|
|
5
|
+
WebSocketLikeConstructor,
|
|
6
|
+
} from './RealtimeClient'
|
|
7
|
+
import RealtimeChannel, {
|
|
8
|
+
RealtimeChannelOptions,
|
|
9
|
+
RealtimeChannelSendResponse,
|
|
10
|
+
RealtimePostgresChangesFilter,
|
|
11
|
+
RealtimePostgresChangesPayload,
|
|
12
|
+
RealtimePostgresInsertPayload,
|
|
13
|
+
RealtimePostgresUpdatePayload,
|
|
14
|
+
RealtimePostgresDeletePayload,
|
|
15
|
+
REALTIME_LISTEN_TYPES,
|
|
16
|
+
REALTIME_POSTGRES_CHANGES_LISTEN_EVENT,
|
|
17
|
+
REALTIME_SUBSCRIBE_STATES,
|
|
18
|
+
REALTIME_CHANNEL_STATES,
|
|
19
|
+
} from './RealtimeChannel'
|
|
20
|
+
import RealtimePresence, {
|
|
21
|
+
RealtimePresenceState,
|
|
22
|
+
RealtimePresenceJoinPayload,
|
|
23
|
+
RealtimePresenceLeavePayload,
|
|
24
|
+
REALTIME_PRESENCE_LISTEN_EVENTS,
|
|
25
|
+
} from './RealtimePresence'
|
|
26
|
+
import WebSocketFactory, { WebSocketLike } from './lib/websocket-factory'
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
RealtimePresence,
|
|
30
|
+
RealtimeChannel,
|
|
31
|
+
RealtimeChannelOptions,
|
|
32
|
+
RealtimeChannelSendResponse,
|
|
33
|
+
RealtimeClient,
|
|
34
|
+
RealtimeClientOptions,
|
|
35
|
+
RealtimeMessage,
|
|
36
|
+
RealtimePostgresChangesFilter,
|
|
37
|
+
RealtimePostgresChangesPayload,
|
|
38
|
+
RealtimePostgresInsertPayload,
|
|
39
|
+
RealtimePostgresUpdatePayload,
|
|
40
|
+
RealtimePostgresDeletePayload,
|
|
41
|
+
RealtimePresenceJoinPayload,
|
|
42
|
+
RealtimePresenceLeavePayload,
|
|
43
|
+
RealtimePresenceState,
|
|
44
|
+
RealtimeRemoveChannelResponse,
|
|
45
|
+
REALTIME_LISTEN_TYPES,
|
|
46
|
+
REALTIME_POSTGRES_CHANGES_LISTEN_EVENT,
|
|
47
|
+
REALTIME_PRESENCE_LISTEN_EVENTS,
|
|
48
|
+
REALTIME_SUBSCRIBE_STATES,
|
|
49
|
+
REALTIME_CHANNEL_STATES,
|
|
50
|
+
WebSocketFactory,
|
|
51
|
+
WebSocketLike,
|
|
52
|
+
WebSocketLikeConstructor,
|
|
53
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { version } from './version'
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_VERSION = `realtime-js/${version}`
|
|
4
|
+
|
|
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
|
|
8
|
+
|
|
9
|
+
export const VERSION = version
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_TIMEOUT = 10000
|
|
12
|
+
|
|
13
|
+
export const WS_CLOSE_NORMAL = 1000
|
|
14
|
+
export const MAX_PUSH_BUFFER_SIZE = 100
|
|
15
|
+
|
|
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
|
+
}
|