Skip to content

Commit 9f7386c

Browse files
authored
Merge pull request #353 from supabase/feat/realtime-subscription
feat: refactor Realtime subscription methods
2 parents 37b1c1e + b6a776f commit 9f7386c

File tree

1 file changed

+42
-69
lines changed

1 file changed

+42
-69
lines changed

src/SupabaseClient.ts

Lines changed: 42 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -131,82 +131,65 @@ export default class SupabaseClient {
131131
}
132132

133133
/**
134-
* Remove all subscriptions.
134+
* Closes and removes all subscriptions and returns a list of removed
135+
* subscriptions and their errors.
135136
*/
136137
async removeAllSubscriptions(): Promise<
137-
(
138-
| {
139-
status: 'fulfilled'
140-
value: {
141-
error: null
142-
}
143-
}
144-
| { status: 'rejected'; reason: { error: Error } }
145-
)[]
138+
{ data: { subscription: RealtimeSubscription }; error: Error | null }[]
146139
> {
147-
const subs: RealtimeSubscription[] = this.realtime.channels.slice()
148-
const removeSubPromises = subs.map((sub: RealtimeSubscription) =>
149-
this.removeSubscription(sub)
150-
.then((): { status: 'fulfilled'; value: { error: null } } => ({
151-
status: 'fulfilled',
152-
value: { error: null },
153-
}))
154-
.catch((reason: { error: Error }): { status: 'rejected'; reason: { error: Error } } => ({
155-
status: 'rejected',
156-
reason,
157-
}))
158-
)
159-
return Promise.all(removeSubPromises)
140+
const allSubs: RealtimeSubscription[] = this.getSubscriptions().slice()
141+
const allSubPromises = allSubs.map((sub) => this.removeSubscription(sub))
142+
const allRemovedSubs = await Promise.all(allSubPromises)
143+
144+
return allRemovedSubs.map(({ error }, i) => {
145+
return {
146+
data: { subscription: allSubs[i] },
147+
error,
148+
}
149+
})
160150
}
161151

162152
/**
163-
* Removes an active subscription and returns the number of open connections.
153+
* Closes and removes a subscription and returns the number of open subscriptions.
164154
*
165-
* @param subscription The subscription you want to remove.
155+
* @param subscription The subscription you want to close and remove.
166156
*/
167-
removeSubscription(subscription: RealtimeSubscription): Promise<
168-
| {
169-
data: { openSubscriptions: number }
170-
error: null
171-
}
172-
| { error: Error }
173-
> {
174-
return new Promise(async (resolve, reject) => {
175-
const { error } = await this._closeSubscription(subscription)
176-
177-
if (error) {
178-
return reject({ error })
179-
}
180-
181-
const allSubscriptions = this.getSubscriptions()
182-
183-
if (allSubscriptions.length === 0) {
184-
const { error } = await this.realtime.disconnect()
185-
186-
if (error) {
187-
return reject({ error })
188-
}
189-
}
157+
async removeSubscription(
158+
subscription: RealtimeSubscription
159+
): Promise<{ data: { openSubscriptions: number }; error: Error | null }> {
160+
const { error } = await this._closeSubscription(subscription)
161+
const allSubs: RealtimeSubscription[] = this.getSubscriptions()
162+
const openSubCount = allSubs.filter((chan) => chan.isJoined()).length
190163

191-
const openSubscriptionsCount = allSubscriptions.filter((chan) => chan.isJoined()).length
164+
if (allSubs.length === 0) await this.realtime.disconnect()
192165

193-
return resolve({
194-
data: { openSubscriptions: openSubscriptionsCount },
195-
error: null,
196-
})
197-
})
166+
return { data: { openSubscriptions: openSubCount }, error }
198167
}
199168

200169
private async _closeSubscription(
201170
subscription: RealtimeSubscription
202-
): Promise<{ error: null | Error }> {
171+
): Promise<{ error: Error | null }> {
172+
let error = null
173+
203174
if (!subscription.isClosed()) {
204-
return await this._closeChannel(subscription)
175+
const { error: unsubError } = await this._unsubscribeSubscription(subscription)
176+
error = unsubError
205177
}
206178

179+
this.realtime.remove(subscription)
180+
181+
return { error }
182+
}
183+
184+
private _unsubscribeSubscription(
185+
subscription: RealtimeSubscription
186+
): Promise<{ error: Error | null }> {
207187
return new Promise((resolve) => {
208-
this.realtime.remove(subscription)
209-
return resolve({ error: null })
188+
subscription
189+
.unsubscribe()
190+
.receive('ok', () => resolve({ error: null }))
191+
.receive('error', (error: Error) => resolve({ error }))
192+
.receive('timeout', () => resolve({ error: new Error('timed out') }))
210193
})
211194
}
212195

@@ -263,16 +246,6 @@ export default class SupabaseClient {
263246
return headers
264247
}
265248

266-
private _closeChannel(subscription: RealtimeSubscription): Promise<{ error: null | Error }> {
267-
return new Promise((resolve, reject) => {
268-
subscription
269-
.unsubscribe()
270-
.receive('ok', () => resolve({ error: null }))
271-
.receive('error', (error: Error) => reject({ error }))
272-
.receive('timeout', () => reject({ error: 'timed out' }))
273-
})
274-
}
275-
276249
private _listenForMultiTabEvents() {
277250
if (!this.multiTab || !isBrowser() || !window?.addEventListener) {
278251
return null
@@ -325,7 +298,7 @@ export default class SupabaseClient {
325298
this.changedAccessToken = token
326299
} else if (event === 'SIGNED_OUT' || event === 'USER_DELETED') {
327300
// Token is removed
328-
this.removeAllSubscriptions()
301+
this.realtime.setAuth(this.supabaseKey)
329302
if (source == 'STORAGE') this.auth.signOut()
330303
}
331304
}

0 commit comments

Comments
 (0)