@@ -42,6 +42,35 @@ export interface DailyVideoCallData {
4242 url : string ;
4343}
4444
45+ // Regions available to create DailyVideo Rooms in.
46+ const REGION_CODES = [
47+ "af-south-1" ,
48+ "ap-northeast-2" ,
49+ "ap-southeast-1" ,
50+ "ap-southeast-2" ,
51+ "ap-south-1" ,
52+ "eu-central-1" ,
53+ "eu-west-2" ,
54+ "sa-east-1" ,
55+ "us-east-1" ,
56+ "us-west-2" ,
57+ ] as const ;
58+
59+ type RoomGeo = ( typeof REGION_CODES ) [ number ] ;
60+
61+ function getDailyVideoRegionFromEnv ( ) : RoomGeo | undefined {
62+ if ( ! process ?. env ?. DAILY_VIDEO_REGION ) return ;
63+ const isRoomGeo = ( value : string ) : value is RoomGeo => REGION_CODES . includes ( value as RoomGeo ) ;
64+ function assertIsDailyVideoRegion ( value : string ) : asserts value is RoomGeo {
65+ if ( ! isRoomGeo ( value ) ) {
66+ throw new Error ( `Invalid region code: ${ value } . Must be one of: ${ REGION_CODES . join ( ", " ) } ` ) ;
67+ }
68+ }
69+ const region = process . env . DAILY_VIDEO_REGION ;
70+ assertIsDailyVideoRegion ( region ) ;
71+ return region ;
72+ }
73+
4574const isS3StorageEnabled =
4675 process . env . CAL_VIDEO_BUCKET_NAME &&
4776 process . env . CAL_VIDEO_BUCKET_REGION &&
@@ -203,11 +232,15 @@ export const setEnableRecordingUIAndUserIdForOrganizer = async (
203232} ;
204233
205234const DailyVideoApiAdapter = ( ) : VideoApiAdapter => {
206- async function createOrUpdateMeeting ( endpoint : string , event : CalendarEvent ) : Promise < VideoCallData > {
235+ async function createOrUpdateMeeting (
236+ endpoint : string ,
237+ event : CalendarEvent ,
238+ region ?: RoomGeo
239+ ) : Promise < VideoCallData > {
207240 if ( ! event . uid ) {
208241 throw new Error ( "We need need the booking uid to create the Daily reference in DB" ) ;
209242 }
210- const body = await translateEvent ( event ) ;
243+ const body = await translateEvent ( event , region ) ;
211244 const dailyEvent = await postToDailyAPI ( endpoint , body ) . then ( dailyReturnTypeSchema . parse ) ;
212245 const meetingToken = await postToDailyAPI ( "/meeting-tokens" , {
213246 properties : {
@@ -226,7 +259,7 @@ const DailyVideoApiAdapter = (): VideoApiAdapter => {
226259 } ) ;
227260 }
228261
229- const translateEvent = async ( event : CalendarEvent ) => {
262+ const translateEvent = async ( event : CalendarEvent , region ?: RoomGeo ) => {
230263 // Documentation at: https://docs.daily.co/reference#list-rooms
231264 // Adds 14 days from the end of the booking as the expiration date
232265 const exp = Math . round ( new Date ( event . endTime ) . getTime ( ) / 1000 ) + 60 * 60 * 24 * 14 ;
@@ -248,6 +281,7 @@ const DailyVideoApiAdapter = (): VideoApiAdapter => {
248281 return {
249282 privacy : "public" ,
250283 properties : {
284+ ...( region ? { geo : region } : { } ) ,
251285 enable_prejoin_ui : true ,
252286 enable_knocking : true ,
253287 enable_screenshare : true ,
@@ -284,7 +318,7 @@ const DailyVideoApiAdapter = (): VideoApiAdapter => {
284318 } ;
285319 } ;
286320
287- async function createInstantMeeting ( endTime : string ) {
321+ async function createInstantMeeting ( endTime : string , region ?: RoomGeo ) {
288322 // added a 1 hour buffer for room expiration
289323 const exp = Math . round ( new Date ( endTime ) . getTime ( ) / 1000 ) + 60 * 60 ;
290324 const { scale_plan : scalePlan } = await getDailyAppKeys ( ) ;
@@ -296,6 +330,7 @@ const DailyVideoApiAdapter = (): VideoApiAdapter => {
296330 const body = {
297331 privacy : "public" ,
298332 properties : {
333+ ...( region ? { geo : region } : { } ) ,
299334 enable_prejoin_ui : true ,
300335 enable_knocking : true ,
301336 enable_screenshare : true ,
@@ -347,20 +382,22 @@ const DailyVideoApiAdapter = (): VideoApiAdapter => {
347382 url : dailyEvent . url ,
348383 } ) ;
349384 }
350-
385+ // Region on which the DailyVideo room is created can be controlled by ENV var
386+ // undefined region leaves the choice to DailyVideo
387+ const region = getDailyVideoRegionFromEnv ( ) ;
351388 return {
352389 /** Daily doesn't need to return busy times, so we return empty */
353390 getAvailability : ( ) => {
354391 return Promise . resolve ( [ ] ) ;
355392 } ,
356393 createMeeting : async ( event : CalendarEvent ) : Promise < VideoCallData > =>
357- createOrUpdateMeeting ( "/rooms" , event ) ,
394+ createOrUpdateMeeting ( "/rooms" , event , region ) ,
358395 deleteMeeting : async ( uid : string ) : Promise < void > => {
359396 await fetcher ( `/rooms/${ uid } ` , { method : "DELETE" } ) ;
360397 return Promise . resolve ( ) ;
361398 } ,
362399 updateMeeting : ( bookingRef : PartialReference , event : CalendarEvent ) : Promise < VideoCallData > =>
363- createOrUpdateMeeting ( `/rooms/${ bookingRef . uid } ` , event ) ,
400+ createOrUpdateMeeting ( `/rooms/${ bookingRef . uid } ` , event , region ) ,
364401 getRecordings : async ( roomName : string ) : Promise < GetRecordingsResponseSchema > => {
365402 try {
366403 const res = await fetcher ( `/recordings?room_name=${ roomName } ` ) . then (
@@ -371,7 +408,7 @@ const DailyVideoApiAdapter = (): VideoApiAdapter => {
371408 throw new Error ( "Something went wrong! Unable to get recording" ) ;
372409 }
373410 } ,
374- createInstantCalVideoRoom : ( endTime : string ) => createInstantMeeting ( endTime ) ,
411+ createInstantCalVideoRoom : ( endTime : string ) => createInstantMeeting ( endTime , region ) ,
375412 getRecordingDownloadLink : async ( recordingId : string ) : Promise < GetAccessLinkResponseSchema > => {
376413 try {
377414 const res = await fetcher ( `/recordings/${ recordingId } /access-link?valid_for_secs=43200` ) . then (
0 commit comments