@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.
- package/dist/main/SupabaseClient.d.ts +33 -27
- package/dist/main/SupabaseClient.d.ts.map +1 -1
- package/dist/main/SupabaseClient.js +70 -69
- package/dist/main/SupabaseClient.js.map +1 -1
- package/dist/main/index.d.ts +6 -5
- package/dist/main/index.d.ts.map +1 -1
- package/dist/main/index.js +3 -2
- package/dist/main/index.js.map +1 -1
- package/dist/main/lib/SupabaseRealtimeClient.d.ts +10 -7
- package/dist/main/lib/SupabaseRealtimeClient.d.ts.map +1 -1
- package/dist/main/lib/SupabaseRealtimeClient.js +42 -28
- package/dist/main/lib/SupabaseRealtimeClient.js.map +1 -1
- package/dist/main/lib/constants.d.ts +0 -1
- package/dist/main/lib/constants.d.ts.map +1 -1
- package/dist/main/lib/constants.js +1 -2
- package/dist/main/lib/constants.js.map +1 -1
- package/dist/main/lib/fetch.d.ts +9 -0
- package/dist/main/lib/fetch.d.ts.map +1 -0
- package/dist/main/lib/fetch.js +75 -0
- package/dist/main/lib/fetch.js.map +1 -0
- package/dist/main/lib/types.d.ts +51 -34
- package/dist/main/lib/types.d.ts.map +1 -1
- package/dist/main/lib/version.d.ts +1 -1
- package/dist/main/lib/version.js +1 -1
- package/dist/module/SupabaseClient.d.ts +33 -27
- package/dist/module/SupabaseClient.d.ts.map +1 -1
- package/dist/module/SupabaseClient.js +71 -70
- package/dist/module/SupabaseClient.js.map +1 -1
- package/dist/module/index.d.ts +6 -5
- package/dist/module/index.d.ts.map +1 -1
- package/dist/module/index.js +2 -2
- package/dist/module/index.js.map +1 -1
- package/dist/module/lib/SupabaseRealtimeClient.d.ts +10 -7
- package/dist/module/lib/SupabaseRealtimeClient.d.ts.map +1 -1
- package/dist/module/lib/SupabaseRealtimeClient.js +42 -28
- package/dist/module/lib/SupabaseRealtimeClient.js.map +1 -1
- package/dist/module/lib/constants.d.ts +0 -1
- package/dist/module/lib/constants.d.ts.map +1 -1
- package/dist/module/lib/constants.js +0 -1
- package/dist/module/lib/constants.js.map +1 -1
- package/dist/module/lib/fetch.d.ts +9 -0
- package/dist/module/lib/fetch.d.ts.map +1 -0
- package/dist/module/lib/fetch.js +46 -0
- package/dist/module/lib/fetch.js.map +1 -0
- package/dist/module/lib/types.d.ts +51 -34
- package/dist/module/lib/types.d.ts.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.js +1 -1
- package/dist/umd/supabase.js +1 -1
- package/package.json +7 -6
- package/src/SupabaseClient.ts +128 -102
- package/src/index.ts +17 -15
- package/src/lib/SupabaseRealtimeClient.ts +50 -33
- package/src/lib/constants.ts +0 -1
- package/src/lib/fetch.ts +47 -0
- package/src/lib/types.ts +53 -36
- package/src/lib/version.ts +1 -1
- package/dist/main/lib/SupabaseQueryBuilder.d.ts +0 -26
- package/dist/main/lib/SupabaseQueryBuilder.d.ts.map +0 -1
- package/dist/main/lib/SupabaseQueryBuilder.js +0 -31
- package/dist/main/lib/SupabaseQueryBuilder.js.map +0 -1
- package/dist/module/lib/SupabaseQueryBuilder.d.ts +0 -26
- package/dist/module/lib/SupabaseQueryBuilder.d.ts.map +0 -1
- package/dist/module/lib/SupabaseQueryBuilder.js +0 -27
- package/dist/module/lib/SupabaseQueryBuilder.js.map +0 -1
- package/dist/umd/98.supabase.js +0 -1
- package/src/lib/SupabaseQueryBuilder.ts +0 -61
package/src/SupabaseClient.ts
CHANGED
|
@@ -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 {
|
|
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.
|
|
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.
|
|
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.
|
|
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<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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<
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
*
|
|
160
|
-
* subscriptions and their errors.
|
|
185
|
+
* Creates a channel with Broadcast and Presence.
|
|
161
186
|
*/
|
|
162
|
-
|
|
163
|
-
|
|
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
|
|
166
|
-
const
|
|
167
|
-
const
|
|
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
|
|
206
|
+
return allRemovedChans.map(({ error }, i) => {
|
|
170
207
|
return {
|
|
171
|
-
data: {
|
|
208
|
+
data: { channels: allChans[i] },
|
|
172
209
|
error,
|
|
173
210
|
}
|
|
174
211
|
})
|
|
175
212
|
}
|
|
176
213
|
|
|
177
214
|
/**
|
|
178
|
-
* Closes and removes a
|
|
215
|
+
* Closes and removes a channel and returns the number of open channels.
|
|
179
216
|
*
|
|
180
|
-
* @param
|
|
217
|
+
* @param channel The channel you want to close and remove.
|
|
181
218
|
*/
|
|
182
|
-
async
|
|
183
|
-
|
|
184
|
-
): Promise<{ data: {
|
|
185
|
-
const { error } = await this.
|
|
186
|
-
const
|
|
187
|
-
const
|
|
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 (
|
|
226
|
+
if (allChans.length === 0) await this.realtime.disconnect()
|
|
190
227
|
|
|
191
|
-
return { data: {
|
|
228
|
+
return { data: { openChannels: openChanCount }, error }
|
|
192
229
|
}
|
|
193
230
|
|
|
194
|
-
private async
|
|
195
|
-
|
|
196
|
-
|
|
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 (!
|
|
200
|
-
const { error: unsubError } = await this.
|
|
240
|
+
if (!channel.isClosed()) {
|
|
241
|
+
const { error: unsubError } = await this._unsubscribeChannel(channel)
|
|
201
242
|
error = unsubError
|
|
202
243
|
}
|
|
203
244
|
|
|
204
|
-
this.realtime.remove(
|
|
245
|
+
this.realtime.remove(channel)
|
|
205
246
|
|
|
206
247
|
return { error }
|
|
207
248
|
}
|
|
208
249
|
|
|
209
|
-
private
|
|
210
|
-
subscription: RealtimeSubscription
|
|
211
|
-
): Promise<{ error: Error | null }> {
|
|
250
|
+
private _unsubscribeChannel(channel: RealtimeChannel): Promise<{ error: Error | null }> {
|
|
212
251
|
return new Promise((resolve) => {
|
|
213
|
-
|
|
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
|
|
261
|
+
* Returns an array of all your channels.
|
|
223
262
|
*/
|
|
224
|
-
|
|
225
|
-
return this.realtime.channels as
|
|
263
|
+
getChannels(): RealtimeChannel[] {
|
|
264
|
+
return this.realtime.channels as RealtimeChannel[]
|
|
226
265
|
}
|
|
227
266
|
|
|
228
|
-
private _initSupabaseAuthClient(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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: { ...
|
|
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 ===
|
|
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
|
|
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 {
|
|
3
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
1
|
+
import { RealtimeChannel, RealtimeClient, Transformers } from '@supabase/realtime-js'
|
|
2
|
+
import { SupabaseRealtimePayload } from './types'
|
|
3
3
|
|
|
4
4
|
export class SupabaseRealtimeClient {
|
|
5
|
-
|
|
5
|
+
socket: RealtimeClient
|
|
6
|
+
channel: RealtimeChannel
|
|
6
7
|
|
|
7
|
-
constructor(socket: RealtimeClient,
|
|
8
|
-
|
|
9
|
-
|
|
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:
|
|
43
|
-
this.
|
|
44
|
-
let enrichedPayload
|
|
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
|
-
|
|
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
|
|
62
|
+
* Enables the channel.
|
|
63
63
|
*/
|
|
64
64
|
subscribe(callback: Function = () => {}) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
this.
|
|
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', () =>
|
|
70
|
-
|
|
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
|
-
|
|
88
|
+
|
|
89
|
+
return this.channel
|
|
73
90
|
}
|
|
74
91
|
}
|
package/src/lib/constants.ts
CHANGED
package/src/lib/fetch.ts
ADDED
|
@@ -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
|
+
}
|