@supabase/supabase-js 1.35.5 → 1.36.0-next.11

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 (67) hide show
  1. package/dist/main/SupabaseClient.d.ts +33 -27
  2. package/dist/main/SupabaseClient.d.ts.map +1 -1
  3. package/dist/main/SupabaseClient.js +70 -69
  4. package/dist/main/SupabaseClient.js.map +1 -1
  5. package/dist/main/index.d.ts +6 -5
  6. package/dist/main/index.d.ts.map +1 -1
  7. package/dist/main/index.js +3 -2
  8. package/dist/main/index.js.map +1 -1
  9. package/dist/main/lib/SupabaseRealtimeClient.d.ts +10 -7
  10. package/dist/main/lib/SupabaseRealtimeClient.d.ts.map +1 -1
  11. package/dist/main/lib/SupabaseRealtimeClient.js +42 -28
  12. package/dist/main/lib/SupabaseRealtimeClient.js.map +1 -1
  13. package/dist/main/lib/constants.d.ts +0 -1
  14. package/dist/main/lib/constants.d.ts.map +1 -1
  15. package/dist/main/lib/constants.js +1 -2
  16. package/dist/main/lib/constants.js.map +1 -1
  17. package/dist/main/lib/fetch.d.ts +9 -0
  18. package/dist/main/lib/fetch.d.ts.map +1 -0
  19. package/dist/main/lib/fetch.js +75 -0
  20. package/dist/main/lib/fetch.js.map +1 -0
  21. package/dist/main/lib/types.d.ts +51 -34
  22. package/dist/main/lib/types.d.ts.map +1 -1
  23. package/dist/main/lib/version.d.ts +1 -1
  24. package/dist/main/lib/version.js +1 -1
  25. package/dist/module/SupabaseClient.d.ts +33 -27
  26. package/dist/module/SupabaseClient.d.ts.map +1 -1
  27. package/dist/module/SupabaseClient.js +71 -70
  28. package/dist/module/SupabaseClient.js.map +1 -1
  29. package/dist/module/index.d.ts +6 -5
  30. package/dist/module/index.d.ts.map +1 -1
  31. package/dist/module/index.js +2 -2
  32. package/dist/module/index.js.map +1 -1
  33. package/dist/module/lib/SupabaseRealtimeClient.d.ts +10 -7
  34. package/dist/module/lib/SupabaseRealtimeClient.d.ts.map +1 -1
  35. package/dist/module/lib/SupabaseRealtimeClient.js +42 -28
  36. package/dist/module/lib/SupabaseRealtimeClient.js.map +1 -1
  37. package/dist/module/lib/constants.d.ts +0 -1
  38. package/dist/module/lib/constants.d.ts.map +1 -1
  39. package/dist/module/lib/constants.js +0 -1
  40. package/dist/module/lib/constants.js.map +1 -1
  41. package/dist/module/lib/fetch.d.ts +9 -0
  42. package/dist/module/lib/fetch.d.ts.map +1 -0
  43. package/dist/module/lib/fetch.js +46 -0
  44. package/dist/module/lib/fetch.js.map +1 -0
  45. package/dist/module/lib/types.d.ts +51 -34
  46. package/dist/module/lib/types.d.ts.map +1 -1
  47. package/dist/module/lib/version.d.ts +1 -1
  48. package/dist/module/lib/version.js +1 -1
  49. package/dist/umd/supabase.js +1 -1
  50. package/package.json +7 -6
  51. package/src/SupabaseClient.ts +128 -102
  52. package/src/index.ts +17 -15
  53. package/src/lib/SupabaseRealtimeClient.ts +50 -33
  54. package/src/lib/constants.ts +0 -1
  55. package/src/lib/fetch.ts +47 -0
  56. package/src/lib/types.ts +53 -36
  57. package/src/lib/version.ts +1 -1
  58. package/dist/main/lib/SupabaseQueryBuilder.d.ts +0 -26
  59. package/dist/main/lib/SupabaseQueryBuilder.d.ts.map +0 -1
  60. package/dist/main/lib/SupabaseQueryBuilder.js +0 -31
  61. package/dist/main/lib/SupabaseQueryBuilder.js.map +0 -1
  62. package/dist/module/lib/SupabaseQueryBuilder.d.ts +0 -26
  63. package/dist/module/lib/SupabaseQueryBuilder.d.ts.map +0 -1
  64. package/dist/module/lib/SupabaseQueryBuilder.js +0 -27
  65. package/dist/module/lib/SupabaseQueryBuilder.js.map +0 -1
  66. package/dist/umd/98.supabase.js +0 -1
  67. package/src/lib/SupabaseQueryBuilder.ts +0 -61
@@ -1,13 +1,18 @@
1
- import { DEFAULT_HEADERS, STORAGE_KEY } from './lib/constants'
2
- import { stripTrailingSlash, isBrowser } from './lib/helpers'
3
- import { Fetch, GenericObject, SupabaseClientOptions } from './lib/types'
4
- import { SupabaseAuthClient } from './lib/SupabaseAuthClient'
5
- import { SupabaseQueryBuilder } from './lib/SupabaseQueryBuilder'
6
- import { SupabaseStorageClient } from '@supabase/storage-js'
7
1
  import { FunctionsClient } from '@supabase/functions-js'
8
- import { PostgrestClient } from '@supabase/postgrest-js'
9
2
  import { AuthChangeEvent } from '@supabase/gotrue-js'
10
- import { RealtimeClient, RealtimeSubscription, RealtimeClientOptions } from '@supabase/realtime-js'
3
+ import {
4
+ PostgrestClient,
5
+ PostgrestFilterBuilder,
6
+ PostgrestQueryBuilder,
7
+ } from '@supabase/postgrest-js'
8
+ import { RealtimeChannel, RealtimeClient, RealtimeClientOptions } from '@supabase/realtime-js'
9
+ import { SupabaseStorageClient } from '@supabase/storage-js'
10
+ import { DEFAULT_HEADERS } from './lib/constants'
11
+ import { fetchWithAuth } from './lib/fetch'
12
+ import { isBrowser, stripTrailingSlash } from './lib/helpers'
13
+ import { SupabaseAuthClient } from './lib/SupabaseAuthClient'
14
+ import { SupabaseRealtimeClient } from './lib/SupabaseRealtimeClient'
15
+ import { Fetch, GenericSchema, SupabaseClientOptions, SupabaseAuthClientOptions } from './lib/types'
11
16
 
12
17
  const DEFAULT_OPTIONS = {
13
18
  schema: 'public',
@@ -23,20 +28,28 @@ const DEFAULT_OPTIONS = {
23
28
  *
24
29
  * An isomorphic Javascript client for interacting with Postgres.
25
30
  */
26
- export default class SupabaseClient {
31
+ export default class SupabaseClient<
32
+ Database = any,
33
+ SchemaName extends string & keyof Database = 'public' extends keyof Database
34
+ ? 'public'
35
+ : string & keyof Database,
36
+ Schema extends GenericSchema = Database[SchemaName] extends GenericSchema
37
+ ? Database[SchemaName]
38
+ : any
39
+ > {
27
40
  /**
28
41
  * Supabase Auth allows you to create and manage user sessions for access to data that is secured by access policies.
29
42
  */
30
43
  auth: SupabaseAuthClient
31
44
 
32
- protected schema: string
33
- protected restUrl: string
34
45
  protected realtimeUrl: string
35
46
  protected authUrl: string
36
47
  protected storageUrl: string
37
48
  protected functionsUrl: string
38
49
  protected realtime: RealtimeClient
50
+ protected rest: PostgrestClient<Database, SchemaName>
39
51
  protected multiTab: boolean
52
+ protected storageKey: string
40
53
  protected fetch?: Fetch
41
54
  protected changedAccessToken: string | undefined
42
55
  protected shouldThrowOnError: boolean
@@ -61,15 +74,13 @@ export default class SupabaseClient {
61
74
  constructor(
62
75
  protected supabaseUrl: string,
63
76
  protected supabaseKey: string,
64
- options?: SupabaseClientOptions
77
+ options?: SupabaseClientOptions<SchemaName>
65
78
  ) {
66
79
  if (!supabaseUrl) throw new Error('supabaseUrl is required.')
67
80
  if (!supabaseKey) throw new Error('supabaseKey is required.')
68
81
 
69
82
  const _supabaseUrl = stripTrailingSlash(supabaseUrl)
70
- const settings = { ...DEFAULT_OPTIONS, ...options }
71
83
 
72
- this.restUrl = `${_supabaseUrl}/rest/v1`
73
84
  this.realtimeUrl = `${_supabaseUrl}/realtime/v1`.replace('http', 'ws')
74
85
  this.authUrl = `${_supabaseUrl}/auth/v1`
75
86
  this.storageUrl = `${_supabaseUrl}/storage/v1`
@@ -81,15 +92,26 @@ export default class SupabaseClient {
81
92
  } else {
82
93
  this.functionsUrl = `${_supabaseUrl}/functions/v1`
83
94
  }
95
+ // default storage key uses the supabase project ref as a namespace
96
+ const defaultStorageKey = `sb-${new URL(this.authUrl).hostname.split('.')[0]}-auth-token`
97
+ this.storageKey = options?.auth?.storageKey ?? defaultStorageKey
98
+
99
+ const settings = { ...DEFAULT_OPTIONS, ...options, storageKey: this.storageKey }
84
100
 
85
- this.schema = settings.schema
86
- this.multiTab = settings.multiTab
87
- this.fetch = settings.fetch
101
+ this.multiTab = settings.auth?.multiTab ?? false
88
102
  this.headers = { ...DEFAULT_HEADERS, ...options?.headers }
89
103
  this.shouldThrowOnError = settings.shouldThrowOnError || false
90
104
 
91
- this.auth = this._initSupabaseAuthClient(settings)
105
+ this.auth = this._initSupabaseAuthClient(settings.auth || {}, this.headers, settings.fetch)
106
+ this.fetch = fetchWithAuth(supabaseKey, this._getAccessToken.bind(this), settings.fetch)
107
+
92
108
  this.realtime = this._initRealtimeClient({ headers: this.headers, ...settings.realtime })
109
+ this.rest = new PostgrestClient(`${_supabaseUrl}/rest/v1`, {
110
+ headers: this.headers,
111
+ schema: options?.db?.schema,
112
+ fetch: this.fetch,
113
+ throwOnError: this.shouldThrowOnError,
114
+ })
93
115
 
94
116
  this._listenForAuthEvents()
95
117
  this._listenForMultiTabEvents()
@@ -105,7 +127,7 @@ export default class SupabaseClient {
105
127
  */
106
128
  get functions() {
107
129
  return new FunctionsClient(this.functionsUrl, {
108
- headers: this._getAuthHeaders(),
130
+ headers: this.headers,
109
131
  customFetch: this.fetch,
110
132
  })
111
133
  }
@@ -114,7 +136,7 @@ export default class SupabaseClient {
114
136
  * Supabase Storage allows you to manage user-generated content, such as photos or videos.
115
137
  */
116
138
  get storage() {
117
- return new SupabaseStorageClient(this.storageUrl, this._getAuthHeaders(), this.fetch)
139
+ return new SupabaseStorageClient(this.storageUrl, this.headers, this.fetch)
118
140
  }
119
141
 
120
142
  /**
@@ -122,16 +144,11 @@ export default class SupabaseClient {
122
144
  *
123
145
  * @param table The table name to operate on.
124
146
  */
125
- from<T = any>(table: string): SupabaseQueryBuilder<T> {
126
- const url = `${this.restUrl}/${table}`
127
- return new SupabaseQueryBuilder<T>(url, {
128
- headers: this._getAuthHeaders(),
129
- schema: this.schema,
130
- realtime: this.realtime,
131
- table,
132
- fetch: this.fetch,
133
- shouldThrowOnError: this.shouldThrowOnError,
134
- })
147
+ from<
148
+ TableName extends string & keyof Schema['Tables'],
149
+ Table extends Schema['Tables'][TableName]
150
+ >(table: TableName): PostgrestQueryBuilder<Table> {
151
+ return this.rest.from(table)
135
152
  }
136
153
 
137
154
  /**
@@ -143,74 +160,96 @@ export default class SupabaseClient {
143
160
  * @param count Count algorithm to use to count rows in a table.
144
161
  *
145
162
  */
146
- rpc<T = any>(
147
- fn: string,
148
- params?: object,
149
- {
150
- head = false,
151
- count = null,
152
- }: { head?: boolean; count?: null | 'exact' | 'planned' | 'estimated' } = {}
153
- ) {
154
- const rest = this._initPostgRESTClient()
155
- return rest.rpc<T>(fn, params, { head, count })
163
+ rpc<
164
+ FunctionName extends string & keyof Schema['Functions'],
165
+ Function_ extends Schema['Functions'][FunctionName]
166
+ >(
167
+ fn: FunctionName,
168
+ args: Function_['Args'] = {},
169
+ options?: {
170
+ head?: boolean
171
+ count?: 'exact' | 'planned' | 'estimated'
172
+ }
173
+ ): PostgrestFilterBuilder<
174
+ Function_['Returns'] extends any[]
175
+ ? Function_['Returns'][number] extends Record<string, unknown>
176
+ ? Function_['Returns'][number]
177
+ : never
178
+ : never,
179
+ Function_['Returns']
180
+ > {
181
+ return this.rest.rpc(fn, args, options)
156
182
  }
157
183
 
158
184
  /**
159
- * Closes and removes all subscriptions and returns a list of removed
160
- * subscriptions and their errors.
185
+ * Creates a channel with Broadcast and Presence.
161
186
  */
162
- async removeAllSubscriptions(): Promise<
163
- { data: { subscription: RealtimeSubscription }; error: Error | null }[]
187
+ channel(name: string, opts?: { [key: string]: any }): SupabaseRealtimeClient {
188
+ if (!this.realtime.isConnected()) {
189
+ this.realtime.connect()
190
+ }
191
+
192
+ return new SupabaseRealtimeClient(this.realtime, name, opts)
193
+ }
194
+
195
+ /**
196
+ * Closes and removes all channels and returns a list of removed
197
+ * channels and their errors.
198
+ */
199
+ async removeAllChannels(): Promise<
200
+ { data: { channels: RealtimeChannel }; error: Error | null }[]
164
201
  > {
165
- const allSubs: RealtimeSubscription[] = this.getSubscriptions().slice()
166
- const allSubPromises = allSubs.map((sub) => this.removeSubscription(sub))
167
- const allRemovedSubs = await Promise.all(allSubPromises)
202
+ const allChans: RealtimeChannel[] = this.getChannels().slice()
203
+ const allChanPromises = allChans.map((chan) => this.removeChannel(chan))
204
+ const allRemovedChans = await Promise.all(allChanPromises)
168
205
 
169
- return allRemovedSubs.map(({ error }, i) => {
206
+ return allRemovedChans.map(({ error }, i) => {
170
207
  return {
171
- data: { subscription: allSubs[i] },
208
+ data: { channels: allChans[i] },
172
209
  error,
173
210
  }
174
211
  })
175
212
  }
176
213
 
177
214
  /**
178
- * Closes and removes a subscription and returns the number of open subscriptions.
215
+ * Closes and removes a channel and returns the number of open channels.
179
216
  *
180
- * @param subscription The subscription you want to close and remove.
217
+ * @param channel The channel you want to close and remove.
181
218
  */
182
- async removeSubscription(
183
- subscription: RealtimeSubscription
184
- ): Promise<{ data: { openSubscriptions: number }; error: Error | null }> {
185
- const { error } = await this._closeSubscription(subscription)
186
- const allSubs: RealtimeSubscription[] = this.getSubscriptions()
187
- const openSubCount = allSubs.filter((chan) => chan.isJoined()).length
219
+ async removeChannel(
220
+ channel: RealtimeChannel
221
+ ): Promise<{ data: { openChannels: number }; error: Error | null }> {
222
+ const { error } = await this._closeChannel(channel)
223
+ const allChans: RealtimeChannel[] = this.getChannels()
224
+ const openChanCount = allChans.filter((chan) => chan.isJoined()).length
188
225
 
189
- if (allSubs.length === 0) await this.realtime.disconnect()
226
+ if (allChans.length === 0) await this.realtime.disconnect()
190
227
 
191
- return { data: { openSubscriptions: openSubCount }, error }
228
+ return { data: { openChannels: openChanCount }, error }
192
229
  }
193
230
 
194
- private async _closeSubscription(
195
- subscription: RealtimeSubscription
196
- ): Promise<{ error: Error | null }> {
231
+ private async _getAccessToken() {
232
+ const { session } = await this.auth.getSession()
233
+
234
+ return session?.access_token ?? null
235
+ }
236
+
237
+ private async _closeChannel(channel: RealtimeChannel): Promise<{ error: Error | null }> {
197
238
  let error = null
198
239
 
199
- if (!subscription.isClosed()) {
200
- const { error: unsubError } = await this._unsubscribeSubscription(subscription)
240
+ if (!channel.isClosed()) {
241
+ const { error: unsubError } = await this._unsubscribeChannel(channel)
201
242
  error = unsubError
202
243
  }
203
244
 
204
- this.realtime.remove(subscription)
245
+ this.realtime.remove(channel)
205
246
 
206
247
  return { error }
207
248
  }
208
249
 
209
- private _unsubscribeSubscription(
210
- subscription: RealtimeSubscription
211
- ): Promise<{ error: Error | null }> {
250
+ private _unsubscribeChannel(channel: RealtimeChannel): Promise<{ error: Error | null }> {
212
251
  return new Promise((resolve) => {
213
- subscription
252
+ channel
214
253
  .unsubscribe()
215
254
  .receive('ok', () => resolve({ error: null }))
216
255
  .receive('error', (error: Error) => resolve({ error }))
@@ -219,22 +258,25 @@ export default class SupabaseClient {
219
258
  }
220
259
 
221
260
  /**
222
- * Returns an array of all your subscriptions.
261
+ * Returns an array of all your channels.
223
262
  */
224
- getSubscriptions(): RealtimeSubscription[] {
225
- return this.realtime.channels as RealtimeSubscription[]
263
+ getChannels(): RealtimeChannel[] {
264
+ return this.realtime.channels as RealtimeChannel[]
226
265
  }
227
266
 
228
- private _initSupabaseAuthClient({
229
- autoRefreshToken,
230
- persistSession,
231
- detectSessionInUrl,
232
- localStorage,
233
- headers,
234
- fetch,
235
- cookieOptions,
236
- multiTab,
237
- }: SupabaseClientOptions) {
267
+ private _initSupabaseAuthClient(
268
+ {
269
+ autoRefreshToken,
270
+ persistSession,
271
+ detectSessionInUrl,
272
+ localStorage,
273
+ cookieOptions,
274
+ multiTab,
275
+ storageKey,
276
+ }: SupabaseAuthClientOptions,
277
+ headers?: Record<string, string>,
278
+ fetch?: Fetch
279
+ ) {
238
280
  const authHeaders = {
239
281
  Authorization: `Bearer ${this.supabaseKey}`,
240
282
  apikey: `${this.supabaseKey}`,
@@ -242,6 +284,7 @@ export default class SupabaseClient {
242
284
  return new SupabaseAuthClient({
243
285
  url: this.authUrl,
244
286
  headers: { ...headers, ...authHeaders },
287
+ storageKey: storageKey,
245
288
  autoRefreshToken,
246
289
  persistSession,
247
290
  detectSessionInUrl,
@@ -255,27 +298,10 @@ export default class SupabaseClient {
255
298
  private _initRealtimeClient(options?: RealtimeClientOptions) {
256
299
  return new RealtimeClient(this.realtimeUrl, {
257
300
  ...options,
258
- params: { ...options?.params, apikey: this.supabaseKey },
301
+ params: { ...{ apikey: this.supabaseKey, vsndate: '2022' }, ...options?.params },
259
302
  })
260
303
  }
261
304
 
262
- private _initPostgRESTClient() {
263
- return new PostgrestClient(this.restUrl, {
264
- headers: this._getAuthHeaders(),
265
- schema: this.schema,
266
- fetch: this.fetch,
267
- throwOnError: this.shouldThrowOnError,
268
- })
269
- }
270
-
271
- private _getAuthHeaders(): GenericObject {
272
- const headers: GenericObject = { ...this.headers }
273
- const authBearer = this.auth.session()?.access_token ?? this.supabaseKey
274
- headers['apikey'] = this.supabaseKey
275
- headers['Authorization'] = headers['Authorization'] || `Bearer ${authBearer}`
276
- return headers
277
- }
278
-
279
305
  private _listenForMultiTabEvents() {
280
306
  if (!this.multiTab || !isBrowser() || !window?.addEventListener) {
281
307
  return null
@@ -283,7 +309,7 @@ export default class SupabaseClient {
283
309
 
284
310
  try {
285
311
  return window?.addEventListener('storage', (e: StorageEvent) => {
286
- if (e.key === STORAGE_KEY) {
312
+ if (e.key === this.storageKey) {
287
313
  const newSession = JSON.parse(String(e.newValue))
288
314
  const accessToken: string | undefined =
289
315
  newSession?.currentSession?.access_token ?? undefined
@@ -304,7 +330,7 @@ export default class SupabaseClient {
304
330
  }
305
331
 
306
332
  private _listenForAuthEvents() {
307
- let { data } = this.auth.onAuthStateChange((event, session) => {
333
+ let data = this.auth.onAuthStateChange((event, session) => {
308
334
  this._handleTokenChanged(event, session?.access_token, 'CLIENT')
309
335
  })
310
336
  return data
package/src/index.ts CHANGED
@@ -1,31 +1,33 @@
1
1
  import SupabaseClient from './SupabaseClient'
2
- import { SupabaseClientOptions, SupabaseRealtimePayload } from './lib/types'
3
- import { User as AuthUser, Session as AuthSession } from '@supabase/gotrue-js'
2
+ import type { GenericSchema, SupabaseClientOptions } from './lib/types'
3
+
4
4
  export * from '@supabase/gotrue-js'
5
- export {
5
+ export type { User as AuthUser, Session as AuthSession } from '@supabase/gotrue-js'
6
+ export type {
6
7
  PostgrestResponse,
7
8
  PostgrestSingleResponse,
8
9
  PostgrestMaybeSingleResponse,
9
10
  PostgrestError,
10
11
  } from '@supabase/postgrest-js'
11
12
  export * from '@supabase/realtime-js'
13
+ export { default as SupabaseClient } from './SupabaseClient'
14
+ export type { SupabaseClientOptions, SupabaseRealtimePayload } from './lib/types'
12
15
 
13
16
  /**
14
17
  * Creates a new Supabase Client.
15
18
  */
16
- const createClient = (
19
+ export const createClient = <
20
+ Database = any,
21
+ SchemaName extends string & keyof Database = 'public' extends keyof Database
22
+ ? 'public'
23
+ : string & keyof Database,
24
+ Schema extends GenericSchema = Database[SchemaName] extends GenericSchema
25
+ ? Database[SchemaName]
26
+ : any
27
+ >(
17
28
  supabaseUrl: string,
18
29
  supabaseKey: string,
19
- options?: SupabaseClientOptions
20
- ): SupabaseClient => {
30
+ options?: SupabaseClientOptions<SchemaName>
31
+ ): SupabaseClient<Database, SchemaName, Schema> => {
21
32
  return new SupabaseClient(supabaseUrl, supabaseKey, options)
22
33
  }
23
-
24
- export {
25
- createClient,
26
- SupabaseClient,
27
- SupabaseClientOptions,
28
- SupabaseRealtimePayload,
29
- AuthUser,
30
- AuthSession,
31
- }
@@ -1,19 +1,13 @@
1
- import { RealtimeSubscription, RealtimeClient, Transformers } from '@supabase/realtime-js'
2
- import { GenericObject, SupabaseEventTypes, SupabaseRealtimePayload } from './types'
1
+ import { RealtimeChannel, RealtimeClient, Transformers } from '@supabase/realtime-js'
2
+ import { SupabaseRealtimePayload } from './types'
3
3
 
4
4
  export class SupabaseRealtimeClient {
5
- subscription: RealtimeSubscription
5
+ socket: RealtimeClient
6
+ channel: RealtimeChannel
6
7
 
7
- constructor(socket: RealtimeClient, headers: GenericObject, schema: string, tableName: string) {
8
- const chanParams: GenericObject = {}
9
- const topic = tableName === '*' ? `realtime:${schema}` : `realtime:${schema}:${tableName}`
10
- const userToken = headers['Authorization'].split(' ')[1]
11
-
12
- if (userToken) {
13
- chanParams['user_token'] = userToken
14
- }
15
-
16
- this.subscription = socket.channel(topic, chanParams) as RealtimeSubscription
8
+ constructor(socket: RealtimeClient, name: string, opts: { [key: string]: any } = {}) {
9
+ this.socket = socket
10
+ this.channel = socket.channel(`realtime:${name}`, opts) as RealtimeChannel
17
11
  }
18
12
 
19
13
  private getPayloadRecords(payload: any) {
@@ -37,38 +31,61 @@ export class SupabaseRealtimeClient {
37
31
  * The event you want to listen to.
38
32
  *
39
33
  * @param event The event
34
+ * @param filter An object that specifies what you want to listen to from the event.
40
35
  * @param callback A callback function that is called whenever the event occurs.
41
36
  */
42
- on(event: SupabaseEventTypes, callback: (payload: SupabaseRealtimePayload<any>) => void) {
43
- this.subscription.on(event, (payload: any) => {
44
- let enrichedPayload: SupabaseRealtimePayload<any> = {
45
- schema: payload.schema,
46
- table: payload.table,
47
- commit_timestamp: payload.commit_timestamp,
48
- eventType: payload.type,
49
- new: {},
50
- old: {},
51
- errors: payload.errors,
52
- }
37
+ on(event: string, filter?: Record<string, string>, callback?: (payload: any) => void) {
38
+ this.channel.on(event, filter ?? {}, ({ payload }: { payload: any }) => {
39
+ let enrichedPayload = payload
53
40
 
54
- enrichedPayload = { ...enrichedPayload, ...this.getPayloadRecords(payload) }
41
+ if (event === 'realtime') {
42
+ const { schema, table, commit_timestamp, type, errors } = enrichedPayload
43
+ enrichedPayload = {
44
+ schema: schema,
45
+ table: table,
46
+ commit_timestamp: commit_timestamp,
47
+ eventType: type,
48
+ new: {},
49
+ old: {},
50
+ errors: errors,
51
+ }
52
+ enrichedPayload = { ...enrichedPayload, ...this.getPayloadRecords(payload) }
53
+ }
55
54
 
56
- callback(enrichedPayload)
55
+ callback && callback(enrichedPayload)
57
56
  })
57
+
58
58
  return this
59
59
  }
60
60
 
61
61
  /**
62
- * Enables the subscription.
62
+ * Enables the channel.
63
63
  */
64
64
  subscribe(callback: Function = () => {}) {
65
- this.subscription.onError((e: Error) => callback('SUBSCRIPTION_ERROR', e))
66
- this.subscription.onClose(() => callback('CLOSED'))
67
- this.subscription
65
+ // if the socket already has a good accessToken
66
+ // we can just use it straight away
67
+ if (this.socket.accessToken) {
68
+ this.channel.updateJoinPayload({
69
+ user_token: this.socket.accessToken,
70
+ })
71
+ }
72
+
73
+ this.channel.onError((e: Error) => callback('CHANNEL_ERROR', e))
74
+ this.channel.onClose(() => callback('CLOSED'))
75
+ this.channel
68
76
  .subscribe()
69
- .receive('ok', () => callback('SUBSCRIBED'))
70
- .receive('error', (e: Error) => callback('SUBSCRIPTION_ERROR', e))
77
+ .receive('ok', () => {
78
+ callback('SUBSCRIBED')
79
+
80
+ // re-set the accessToken again in case it was set while
81
+ // the subscription was isJoining
82
+ if (this.socket.accessToken) {
83
+ this.socket.setAuth(this.socket.accessToken)
84
+ }
85
+ })
86
+ .receive('error', (e: Error) => callback('CHANNEL_ERROR', e))
71
87
  .receive('timeout', () => callback('RETRYING_AFTER_TIMEOUT'))
72
- return this.subscription
88
+
89
+ return this.channel
73
90
  }
74
91
  }
@@ -1,4 +1,3 @@
1
1
  // constants.ts
2
2
  import { version } from './version'
3
3
  export const DEFAULT_HEADERS = { 'X-Client-Info': `supabase-js/${version}` }
4
- export const STORAGE_KEY = 'supabase.auth.token'
@@ -0,0 +1,47 @@
1
+ import crossFetch, { Headers as CrossFetchHeaders } from 'cross-fetch'
2
+
3
+ type Fetch = typeof fetch
4
+
5
+ export const resolveFetch = (customFetch?: Fetch): Fetch => {
6
+ let _fetch: Fetch
7
+ if (customFetch) {
8
+ _fetch = customFetch
9
+ } else if (typeof fetch === 'undefined') {
10
+ _fetch = crossFetch as unknown as Fetch
11
+ } else {
12
+ _fetch = fetch
13
+ }
14
+ return (...args) => _fetch(...args)
15
+ }
16
+
17
+ export const resolveHeadersConstructor = () => {
18
+ if (typeof Headers === 'undefined') {
19
+ return CrossFetchHeaders
20
+ }
21
+
22
+ return Headers
23
+ }
24
+
25
+ export const fetchWithAuth = (
26
+ supabaseKey: string,
27
+ getAccessToken: () => Promise<string | null>,
28
+ customFetch?: Fetch
29
+ ): Fetch => {
30
+ const fetch = resolveFetch(customFetch)
31
+ const HeadersConstructor = resolveHeadersConstructor()
32
+
33
+ return async (input, init) => {
34
+ const accessToken = (await getAccessToken()) ?? supabaseKey
35
+ let headers = new HeadersConstructor(init?.headers)
36
+
37
+ if (!headers.has('apikey')) {
38
+ headers.set('apikey', supabaseKey)
39
+ }
40
+
41
+ if (!headers.has('Authorization')) {
42
+ headers.set('Authorization', `Bearer ${accessToken}`)
43
+ }
44
+
45
+ return fetch(input, { ...init, headers })
46
+ }
47
+ }