Skip to content

Commit 3fb82a1

Browse files
author
lyc
committed
chore(lib/fetch): dynamic import @supabase/node-fetch (#1303)
1 parent 4c7f571 commit 3fb82a1

File tree

3 files changed

+100
-26
lines changed

3 files changed

+100
-26
lines changed

src/lib/fetch.ts

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,17 @@
1-
// @ts-ignore
2-
import nodeFetch, { Headers as NodeFetchHeaders } from '@supabase/node-fetch'
3-
4-
type Fetch = typeof fetch
5-
6-
export const resolveFetch = (customFetch?: Fetch): Fetch => {
7-
let _fetch: Fetch
8-
if (customFetch) {
9-
_fetch = customFetch
10-
} else if (typeof fetch === 'undefined') {
11-
_fetch = nodeFetch as unknown as Fetch
12-
} else {
13-
_fetch = fetch
14-
}
15-
return (...args: Parameters<Fetch>) => _fetch(...args)
16-
}
17-
18-
export const resolveHeadersConstructor = () => {
19-
if (typeof Headers === 'undefined') {
20-
return NodeFetchHeaders
21-
}
22-
23-
return Headers
24-
}
1+
import { resolveFetch, resolveHeadersConstructor } from './helpers'
2+
import { Fetch } from './types'
253

264
export const fetchWithAuth = (
275
supabaseKey: string,
286
getAccessToken: () => Promise<string | null>,
297
customFetch?: Fetch
308
): Fetch => {
319
const fetch = resolveFetch(customFetch)
32-
const HeadersConstructor = resolveHeadersConstructor()
3310

3411
return async (input, init) => {
3512
const accessToken = (await getAccessToken()) ?? supabaseKey
13+
14+
const HeadersConstructor = await resolveHeadersConstructor()
3615
let headers = new HeadersConstructor(init?.headers)
3716

3817
if (!headers.has('apikey')) {

src/lib/helpers.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// helpers.ts
2-
import { SupabaseClientOptions } from './types'
2+
import { Fetch, SupabaseClientOptions } from './types'
33

44
export function uuid() {
55
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
@@ -66,3 +66,26 @@ export function applySettingDefaults<
6666

6767
return result
6868
}
69+
70+
export const resolveFetch = (customFetch?: Fetch): Fetch => {
71+
let _fetch: Fetch
72+
if (customFetch) {
73+
_fetch = customFetch
74+
} else if (typeof fetch === 'undefined') {
75+
_fetch = (...args) =>
76+
import('@supabase/node-fetch' as any).then(({ default: fetch }) => fetch(...args))
77+
} else {
78+
_fetch = fetch
79+
}
80+
return (...args: Parameters<Fetch>) => _fetch(...args)
81+
}
82+
83+
export const resolveHeadersConstructor = async () => {
84+
if (typeof Headers === 'undefined') {
85+
return import('@supabase/node-fetch' as any).then(
86+
({ Headers: NodeFetchHeaders }) => NodeFetchHeaders as typeof Headers
87+
)
88+
}
89+
90+
return Headers
91+
}

test/helpers.test.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,75 @@ test('override setting defaults', async () => {
4040
// Existing property values should remain constant
4141
expect(settings.db.schema).toBe(defaults.db.schema)
4242
})
43+
44+
describe('resolveFetch', () => {
45+
const TEST_URL = 'https://example.com'
46+
const TEST_OPTIONS = { method: 'GET' }
47+
48+
beforeEach(() => {
49+
// Reset any mocks between tests
50+
jest.resetModules()
51+
jest.clearAllMocks()
52+
})
53+
54+
test('should use custom fetch if provided', async () => {
55+
const customFetch = jest.fn()
56+
const resolvedFetch = helpers.resolveFetch(customFetch)
57+
58+
await resolvedFetch(TEST_URL, TEST_OPTIONS)
59+
60+
expect(customFetch).toHaveBeenCalledTimes(1)
61+
expect(customFetch).toHaveBeenCalledWith(TEST_URL, TEST_OPTIONS)
62+
})
63+
64+
test('should use global fetch if no custom fetch is provided', async () => {
65+
const globalFetch = jest.fn()
66+
global.fetch = globalFetch
67+
const resolvedFetch = helpers.resolveFetch()
68+
69+
await resolvedFetch(TEST_URL, TEST_OPTIONS)
70+
71+
expect(globalFetch).toHaveBeenCalledTimes(1)
72+
expect(globalFetch).toHaveBeenCalledWith(TEST_URL, TEST_OPTIONS)
73+
})
74+
75+
test('should use node-fetch if global fetch is not available', async () => {
76+
const nodeFetch = jest.fn()
77+
jest.mock('@supabase/node-fetch', () => nodeFetch)
78+
79+
global.fetch = undefined as any
80+
const resolvedFetch = helpers.resolveFetch()
81+
82+
await resolvedFetch(TEST_URL, TEST_OPTIONS)
83+
84+
expect(nodeFetch).toHaveBeenCalledTimes(1)
85+
expect(nodeFetch).toHaveBeenCalledWith(TEST_URL, TEST_OPTIONS)
86+
})
87+
})
88+
89+
describe('resolveHeadersConstructor', () => {
90+
beforeEach(() => {
91+
// Reset any mocks between tests
92+
jest.resetModules()
93+
jest.clearAllMocks()
94+
})
95+
96+
test('should use Headers if available', async () => {
97+
const resolvedHeadersConstructor = await helpers.resolveHeadersConstructor()
98+
expect(resolvedHeadersConstructor).toBe(Headers)
99+
})
100+
101+
test('should use node-fetch Headers if global Headers is not available', async () => {
102+
const MockHeaders = jest.fn()
103+
jest.mock('@supabase/node-fetch', () => ({
104+
Headers: MockHeaders,
105+
}))
106+
107+
// Cannot assign read-only property, delete is available
108+
// @ts-ignore
109+
delete global.Headers
110+
111+
const resolvedHeadersConstructor = await helpers.resolveHeadersConstructor()
112+
expect(resolvedHeadersConstructor).toBe(MockHeaders)
113+
})
114+
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy