import {
CustomRateLimitDetails,
ZoneCache,
ZuploContext,
ZuploRequest,
environment,
} from "@zuplo/runtime" ;
import { createClient } from "@supabase/supabase-js" ;
const CACHE_NAME = "rate-limit-requests-allowed-cache" ;
const SB_URL = "https://YOUR_SUPABASE_URL.supabase.co" ;
const SB_SERVICE_ROLE_KEY = environment. SB_SERVICE_ROLE_KEY ;
const FALLBACK_REQUESTS_ALLOWED = 100 ;
export async function rateLimitKey (
request : ZuploRequest ,
context : ZuploContext ,
policyName : string ,
) : Promise < CustomRateLimitDetails > {
// We'll get the customer ID from the user data.
// This might be from a JWT or API Key metadata
const customerId = request.user.data.customerId;
// We don't want to hit the database on every request
// So we'll use the fast zone cache to cache this data
const cache = new ZoneCache ( CACHE_NAME , context);
let requestsAllowed = await cache. get (customerId);
// If we didn't get a value, we'll need to go to the database
// In this example we're using supabase, but you could use your
// own API, Xata, etc.
if (requestsAllowed === undefined ) {
// create the supabase client and read the customer's
const supabase = createClient ( SB_URL , SB_SERVICE_ROLE_KEY );
let { data, error } = await supabase
. from ( "customer_rate_limits" )
. select ( "requestsAllowed" )
. eq ( "customerId" , customerId);
// If something goes wrong, we probably want to log an
// error and assume a default, vs go down
if (error) {
context.log. error (error);
requestsAllowed = FALLBACK_REQUESTS_ALLOWED ;
} else {
context.log. info (data);
requestsAllowed = data[ 0 ].requestsAllowed;
}
// store the read value in the ZoneCache
// do this asynchronously to improve performance
cache
. put (customerId, requestsAllowed, 60 )
. catch (( err ) => context.log. error (err));
}
return {
key: customerId,
requestsAllowed: requestsAllowed,
timeWindowMinutes: 1 ,
};
}