Skip to content

Commit 45f40ae

Browse files
authored
Merge pull request #75 from supabase/feat-add-regional-options
Feat add regional options
2 parents 1470363 + 4a5b2d3 commit 45f40ae

File tree

3 files changed

+187
-2
lines changed

3 files changed

+187
-2
lines changed

src/FunctionsClient.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,30 @@ import {
66
FunctionsRelayError,
77
FunctionsResponse,
88
FunctionInvokeOptions,
9+
FunctionRegion,
910
} from './types'
1011

1112
export class FunctionsClient {
1213
protected url: string
1314
protected headers: Record<string, string>
15+
protected region: FunctionRegion
1416
protected fetch: Fetch
1517

1618
constructor(
1719
url: string,
1820
{
1921
headers = {},
2022
customFetch,
23+
region = FunctionRegion.Any,
2124
}: {
2225
headers?: Record<string, string>
2326
customFetch?: Fetch
27+
region?: FunctionRegion
2428
} = {}
2529
) {
2630
this.url = url
2731
this.headers = headers
32+
this.region = region
2833
this.fetch = resolveFetch(customFetch)
2934
}
3035

@@ -47,8 +52,14 @@ export class FunctionsClient {
4752
): Promise<FunctionsResponse<T>> {
4853
try {
4954
const { headers, method, body: functionArgs } = options
50-
5155
let _headers: Record<string, string> = {}
56+
let { region } = options
57+
if (!region) {
58+
region = this.region
59+
}
60+
if (region && region !== 'any') {
61+
_headers['x-region'] = region
62+
}
5263
let body: any
5364
if (
5465
functionArgs &&

src/types.ts

+22
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@ export class FunctionsHttpError extends FunctionsError {
4040
super('Edge Function returned a non-2xx status code', 'FunctionsHttpError', context)
4141
}
4242
}
43+
// Define the enum for the 'region' property
44+
export enum FunctionRegion {
45+
Any = 'any',
46+
ApNortheast1 = 'ap-northeast-1',
47+
ApNortheast2 = 'ap-northeast-2',
48+
ApSouth1 = 'ap-south-1',
49+
ApSoutheast1 = 'ap-southeast-1',
50+
ApSoutheast2 = 'ap-southeast-2',
51+
CaCentral1 = 'ca-central-1',
52+
EuCentral1 = 'eu-central-1',
53+
EuWest1 = 'eu-west-1',
54+
EuWest2 = 'eu-west-2',
55+
EuWest3 = 'eu-west-3',
56+
SaEast1 = 'sa-east-1',
57+
UsEast1 = 'us-east-1',
58+
UsWest1 = 'us-west-1',
59+
UsWest2 = 'us-west-2',
60+
}
4361

4462
export type FunctionInvokeOptions = {
4563
/**
@@ -50,6 +68,10 @@ export type FunctionInvokeOptions = {
5068
* The HTTP verb of the request
5169
*/
5270
method?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE'
71+
/**
72+
* The Region to invoke the function in.
73+
*/
74+
region?: FunctionRegion;
5375
/**
5476
* The body of the request.
5577
*/

test/spec/params.spec.ts

+153-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { sign } from 'jsonwebtoken'
77
import { ContentType } from 'allure-js-commons'
88

99
import { FunctionsClient } from '../../src/index'
10-
10+
import { FunctionRegion } from '../../src/types'
1111
import { Relay, runRelay } from '../relay/container'
1212
import { attach, log } from '../utils/jest-custom-reporter'
1313
import { str2ab } from '../utils/binaries'
@@ -146,6 +146,158 @@ describe('params reached to function', () => {
146146
).toBe(true)
147147
})
148148

149+
test('invoke mirror set valid region on request', async () => {
150+
/**
151+
* @feature headers
152+
*/
153+
log('create FunctionsClient')
154+
const fclient = new FunctionsClient(`http://localhost:${relay.container.getMappedPort(8081)}`)
155+
156+
log('invoke mirror')
157+
const customHeader = nanoid()
158+
const validRegion = FunctionRegion.ApNortheast1
159+
160+
const { data, error } = await fclient.invoke<MirrorResponse>('mirror', {
161+
headers: {
162+
'custom-header': customHeader,
163+
Authorization: `Bearer ${apiKey}`,
164+
},
165+
region: validRegion,
166+
})
167+
168+
log('assert no error')
169+
const expected = {
170+
url: 'http://localhost:8000/mirror',
171+
method: 'POST',
172+
headers: data?.headers ?? [],
173+
body: '',
174+
}
175+
expect(data).toEqual(expected)
176+
attach(
177+
'check headers from function',
178+
`expected to include: ${['custom-header', customHeader]}\n actual: ${JSON.stringify(
179+
data?.headers
180+
)}`,
181+
ContentType.TEXT
182+
)
183+
console.log(data?.headers)
184+
expect(
185+
(data?.headers as [Array<string>]).filter(([k, v]) => k === 'x-region' && v === validRegion)
186+
.length > 0
187+
).toBe(true)
188+
})
189+
190+
test('invoke with region overrides region in the client', async () => {
191+
/**
192+
* @feature headers
193+
*/
194+
log('create FunctionsClient')
195+
const fclient = new FunctionsClient(`http://localhost:${relay.container.getMappedPort(8081)}`, {
196+
region: FunctionRegion.ApNortheast1,
197+
})
198+
199+
log('invoke mirror')
200+
const customHeader = nanoid()
201+
const validRegion = FunctionRegion.ApSoutheast1
202+
203+
const { data, error } = await fclient.invoke<MirrorResponse>('mirror', {
204+
headers: {
205+
'custom-header': customHeader,
206+
Authorization: `Bearer ${apiKey}`,
207+
},
208+
region: validRegion,
209+
})
210+
211+
log('assert no error')
212+
const expected = {
213+
url: 'http://localhost:8000/mirror',
214+
method: 'POST',
215+
headers: data?.headers ?? [],
216+
body: '',
217+
}
218+
expect(data).toEqual(expected)
219+
attach(
220+
'check headers from function',
221+
`expected to include: ${['custom-header', customHeader]}\n actual: ${JSON.stringify(
222+
data?.headers
223+
)}`,
224+
ContentType.TEXT
225+
)
226+
console.log(data?.headers)
227+
expect(
228+
(data?.headers as [Array<string>]).filter(([k, v]) => k === 'x-region' && v === validRegion)
229+
.length > 0
230+
).toBe(true)
231+
})
232+
233+
test('starts client with default region, invoke reverts to any (no x-region header)', async () => {
234+
/**
235+
* @feature headers
236+
*/
237+
log('create FunctionsClient')
238+
const validRegion = FunctionRegion.ApSoutheast1
239+
const fclient = new FunctionsClient(`http://localhost:${relay.container.getMappedPort(8081)}`, {
240+
region: validRegion,
241+
})
242+
243+
log('invoke mirror')
244+
const customHeader = nanoid()
245+
246+
const { data, error } = await fclient.invoke<MirrorResponse>('mirror', {
247+
headers: {
248+
'custom-header': customHeader,
249+
Authorization: `Bearer ${apiKey}`,
250+
},
251+
region: FunctionRegion.Any
252+
})
253+
254+
log('assert no error')
255+
const expected = {
256+
url: 'http://localhost:8000/mirror',
257+
method: 'POST',
258+
headers: data?.headers ?? [],
259+
body: '',
260+
}
261+
expect(data).toEqual(expected)
262+
attach(
263+
'check headers from function',
264+
`expected to include: ${['custom-header', customHeader]}\n actual: ${JSON.stringify(
265+
data?.headers
266+
)}`,
267+
ContentType.TEXT
268+
)
269+
console.log(data?.headers)
270+
expect(
271+
(data?.headers as [Array<string>]).filter(([k, v]) => k === 'x-region' && v === validRegion)
272+
.length == 0
273+
).toBe(true)
274+
})
275+
276+
test('invoke region set only on the constructor', async () => {
277+
/**
278+
* @feature headers
279+
*/
280+
log('create FunctionsClient')
281+
const fclient = new FunctionsClient(`http://localhost:${relay.container.getMappedPort(8081)}`,{region: FunctionRegion.ApNortheast1})
282+
283+
log('invoke mirror')
284+
const customHeader = nanoid()
285+
286+
287+
const { data, error } = await fclient.invoke<MirrorResponse>('mirror', {
288+
headers: {
289+
'custom-header': customHeader,
290+
Authorization: `Bearer ${apiKey}`
291+
},
292+
})
293+
294+
log('assert no error')
295+
expect(
296+
(data?.headers as [Array<string>]).filter(([k, v]) => k === 'x-region' && v === FunctionRegion.ApNortheast1)
297+
.length > 0
298+
).toBe(true)
299+
})
300+
149301
test('invoke mirror with body formData', async () => {
150302
/**
151303
* @feature body

0 commit comments

Comments
 (0)