@supabase/supabase-js 2.110.3 → 2.110.4-canary.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/dist/index.cjs +41 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +7 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +41 -9
- package/dist/index.mjs.map +1 -1
- package/dist/umd/supabase.js +7 -7
- package/package.json +6 -6
- package/src/SupabaseClient.ts +28 -5
- package/src/lib/fetch.ts +38 -3
- package/src/lib/version.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supabase/supabase-js",
|
|
3
|
-
"version": "2.110.
|
|
3
|
+
"version": "2.110.4-canary.0",
|
|
4
4
|
"description": "Isomorphic Javascript SDK for Supabase",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"javascript",
|
|
@@ -59,11 +59,11 @@
|
|
|
59
59
|
"directory": "packages/core/supabase-js"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@supabase/auth-js": "2.110.
|
|
63
|
-
"@supabase/functions-js": "2.110.
|
|
64
|
-
"@supabase/postgrest-js": "2.110.
|
|
65
|
-
"@supabase/
|
|
66
|
-
"@supabase/
|
|
62
|
+
"@supabase/auth-js": "2.110.4-canary.0",
|
|
63
|
+
"@supabase/functions-js": "2.110.4-canary.0",
|
|
64
|
+
"@supabase/postgrest-js": "2.110.4-canary.0",
|
|
65
|
+
"@supabase/realtime-js": "2.110.4-canary.0",
|
|
66
|
+
"@supabase/storage-js": "2.110.4-canary.0"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@arethetypeswrong/cli": "^0.18.2",
|
package/src/SupabaseClient.ts
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
DEFAULT_REALTIME_OPTIONS,
|
|
21
21
|
DEFAULT_TRACE_PROPAGATION_OPTIONS,
|
|
22
22
|
} from './lib/constants'
|
|
23
|
-
import { fetchWithAuth } from './lib/fetch'
|
|
23
|
+
import { assertSupportedApiKey, fetchWithAuth } from './lib/fetch'
|
|
24
24
|
import {
|
|
25
25
|
applySettingDefaults,
|
|
26
26
|
validateSupabaseUrl,
|
|
@@ -89,6 +89,7 @@ export default class SupabaseClient<
|
|
|
89
89
|
protected rest: PostgrestClient<Database, ClientOptions, SchemaName>
|
|
90
90
|
protected storageKey: string
|
|
91
91
|
protected fetch?: Fetch
|
|
92
|
+
protected functionsFetch?: Fetch
|
|
92
93
|
protected changedAccessToken?: string
|
|
93
94
|
protected accessToken?: () => Promise<string | null>
|
|
94
95
|
|
|
@@ -314,6 +315,7 @@ export default class SupabaseClient<
|
|
|
314
315
|
) {
|
|
315
316
|
const baseUrl = validateSupabaseUrl(supabaseUrl)
|
|
316
317
|
if (!supabaseKey) throw new Error('supabaseKey is required.')
|
|
318
|
+
assertSupportedApiKey(supabaseKey)
|
|
317
319
|
|
|
318
320
|
this.realtimeUrl = new URL('realtime/v1', baseUrl)
|
|
319
321
|
this.realtimeUrl.protocol = this.realtimeUrl.protocol.replace('http', 'ws')
|
|
@@ -357,13 +359,25 @@ export default class SupabaseClient<
|
|
|
357
359
|
})
|
|
358
360
|
}
|
|
359
361
|
|
|
362
|
+
// The fetch wrappers receive the raw session token (null when there is no session) and
|
|
363
|
+
// decide the `Authorization` fallback themselves, so the API-key fallback lives in one place.
|
|
360
364
|
this.fetch = fetchWithAuth(
|
|
361
365
|
supabaseKey,
|
|
362
366
|
supabaseUrl,
|
|
363
|
-
this.
|
|
367
|
+
this._getSessionToken.bind(this),
|
|
364
368
|
settings.global.fetch,
|
|
365
369
|
settings.tracePropagation
|
|
366
370
|
)
|
|
371
|
+
// Edge Functions use a dedicated fetch that never falls back to a new-format API key in
|
|
372
|
+
// the Authorization header (see `isNewApiKey` in ./lib/fetch). Other services use `this.fetch`.
|
|
373
|
+
this.functionsFetch = fetchWithAuth(
|
|
374
|
+
supabaseKey,
|
|
375
|
+
supabaseUrl,
|
|
376
|
+
this._getSessionToken.bind(this),
|
|
377
|
+
settings.global.fetch,
|
|
378
|
+
settings.tracePropagation,
|
|
379
|
+
{ omitApiKeyAsBearer: true }
|
|
380
|
+
)
|
|
367
381
|
this.realtime = this._initRealtimeClient({
|
|
368
382
|
headers: this.headers,
|
|
369
383
|
accessToken: this._getAccessToken.bind(this),
|
|
@@ -404,7 +418,7 @@ export default class SupabaseClient<
|
|
|
404
418
|
get functions(): FunctionsClient {
|
|
405
419
|
return new FunctionsClient(this.functionsUrl.href, {
|
|
406
420
|
headers: this.headers,
|
|
407
|
-
customFetch: this.
|
|
421
|
+
customFetch: this.functionsFetch,
|
|
408
422
|
})
|
|
409
423
|
}
|
|
410
424
|
|
|
@@ -568,14 +582,23 @@ export default class SupabaseClient<
|
|
|
568
582
|
return this.realtime.removeAllChannels()
|
|
569
583
|
}
|
|
570
584
|
|
|
571
|
-
|
|
585
|
+
/**
|
|
586
|
+
* The raw session token — the custom `accessToken` result or the signed-in user's JWT —
|
|
587
|
+
* or `null` when there is no session. Unlike {@link _getAccessToken} it does not fall back
|
|
588
|
+
* to `supabaseKey`, so callers can distinguish "no session" from "has session".
|
|
589
|
+
*/
|
|
590
|
+
private async _getSessionToken(): Promise<string | null> {
|
|
572
591
|
if (this.accessToken) {
|
|
573
592
|
return await this.accessToken()
|
|
574
593
|
}
|
|
575
594
|
|
|
576
595
|
const { data } = await this.auth.getSession()
|
|
577
596
|
|
|
578
|
-
return data.session?.access_token ??
|
|
597
|
+
return data.session?.access_token ?? null
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private async _getAccessToken() {
|
|
601
|
+
return (await this._getSessionToken()) ?? this.supabaseKey
|
|
579
602
|
}
|
|
580
603
|
|
|
581
604
|
private _initSupabaseAuthClient(
|
package/src/lib/fetch.ts
CHANGED
|
@@ -21,12 +21,39 @@ export const resolveHeadersConstructor = () => {
|
|
|
21
21
|
return Headers
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* New-format Supabase API keys (`sb_publishable_…` / `sb_secret_…`) are not JWTs and
|
|
26
|
+
* must never be sent as a Bearer token — they belong only in the `apikey` header.
|
|
27
|
+
* Legacy (JWT) keys predate this format (they don't start with `sb_`) and keep their
|
|
28
|
+
* existing behavior. Any other `sb_`-prefixed key is an unrecognized future subtype;
|
|
29
|
+
* see {@link assertSupportedApiKey}.
|
|
30
|
+
*/
|
|
31
|
+
const isNewApiKey = (key: string): boolean =>
|
|
32
|
+
key.startsWith('sb_publishable_') || key.startsWith('sb_secret_')
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Fail fast on an `sb_`-family key whose subtype this SDK version does not recognize, so a
|
|
36
|
+
* future key type can never be silently mistreated as a legacy JWT and sent as a Bearer
|
|
37
|
+
* token. Recognized new-format keys and legacy JWT keys (no `sb_` prefix) pass through.
|
|
38
|
+
* The key itself is never included in the message to avoid leaking secret keys.
|
|
39
|
+
*/
|
|
40
|
+
export const assertSupportedApiKey = (key: string): void => {
|
|
41
|
+
if (key.startsWith('sb_') && !isNewApiKey(key)) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
'@supabase/supabase-js: Unrecognized Supabase API key format. Expected a legacy JWT key ' +
|
|
44
|
+
'or a new-format key (sb_publishable_… / sb_secret_…). This "sb_" key type is not ' +
|
|
45
|
+
'supported by this version of the SDK — please upgrade @supabase/supabase-js.'
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
24
50
|
export const fetchWithAuth = (
|
|
25
51
|
supabaseKey: string,
|
|
26
52
|
supabaseUrl: string,
|
|
27
53
|
getAccessToken: () => Promise<string | null>,
|
|
28
54
|
customFetch?: Fetch,
|
|
29
|
-
tracePropagationOptions?: TracePropagationOptions
|
|
55
|
+
tracePropagationOptions?: TracePropagationOptions,
|
|
56
|
+
options?: { omitApiKeyAsBearer?: boolean }
|
|
30
57
|
): Fetch => {
|
|
31
58
|
const fetch = resolveFetch(customFetch)
|
|
32
59
|
const HeadersConstructor = resolveHeadersConstructor()
|
|
@@ -39,8 +66,13 @@ export const fetchWithAuth = (
|
|
|
39
66
|
? getDefaultPropagationTargets(supabaseUrl)
|
|
40
67
|
: null
|
|
41
68
|
|
|
69
|
+
// Whether the API key may be used as the `Authorization` Bearer fallback when there is no
|
|
70
|
+
// session token. Disabled for Edge Functions with a new-format key (see `isNewApiKey`).
|
|
71
|
+
// Static per instance, so it is computed once here rather than on every request.
|
|
72
|
+
const allowKeyAsBearer = !(options?.omitApiKeyAsBearer && isNewApiKey(supabaseKey))
|
|
73
|
+
|
|
42
74
|
return async (input, init) => {
|
|
43
|
-
const
|
|
75
|
+
const realToken = await getAccessToken()
|
|
44
76
|
let headers = new HeadersConstructor(init?.headers)
|
|
45
77
|
|
|
46
78
|
if (!headers.has('apikey')) {
|
|
@@ -48,7 +80,10 @@ export const fetchWithAuth = (
|
|
|
48
80
|
}
|
|
49
81
|
|
|
50
82
|
if (!headers.has('Authorization')) {
|
|
51
|
-
|
|
83
|
+
const bearer = realToken ?? (allowKeyAsBearer ? supabaseKey : null)
|
|
84
|
+
if (bearer) {
|
|
85
|
+
headers.set('Authorization', `Bearer ${bearer}`)
|
|
86
|
+
}
|
|
52
87
|
}
|
|
53
88
|
|
|
54
89
|
if (traceTargets) {
|
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.110.
|
|
7
|
+
export const version = '2.110.4-canary.0'
|