cache middleware

This commit is contained in:
2026-01-27 13:45:10 -03:00
parent 9ad9457260
commit 028297443a
2 changed files with 61 additions and 13 deletions

View File

@@ -22,6 +22,7 @@ export type WorkspaceContextProps = {
subscription: Subscription | null subscription: Subscription | null
address: Address | null address: Address | null
test_mode: boolean test_mode: boolean
blocked: boolean
} }
type HttpResponse = { type HttpResponse = {
@@ -33,18 +34,23 @@ type HttpResponse = {
preferred_org_id?: string preferred_org_id?: string
} }
export const workspaceContext = createContext< export const workspaceContext = createContext<WorkspaceContextProps>()
WorkspaceContextProps & { blocked: boolean }
>()
export const workspaceMiddleware = async ( export const workspaceMiddleware = async (
{ params, request, context }: LoaderFunctionArgs, { params, request, context }: LoaderFunctionArgs,
next: () => Promise<Response> next: () => Promise<Response>
): Promise<Response> => { ): Promise<Response> => {
const url = new URL(request.url) const orgId = params.orgid
const user = context.get(userContext)! const user = context.get(userContext)!
console.debug('Hit on workspace middelware') const cacheKey = buildWorkspaceCacheKey(request, user.sub, orgId)
const cached = await getFromCache(cacheKey)
if (cached) {
context.set(workspaceContext, cached)
return next()
}
const r = await req({ const r = await req({
url: `/users/${user.sub}/orgs?limit=25`, url: `/users/${user.sub}/orgs?limit=25`,
request, request,
@@ -61,9 +67,10 @@ export const workspaceMiddleware = async (
return { id, name, cnpj } return { id, name, cnpj }
}) })
const activeWorkspace = workspaces.find(({ id }) => id === params.orgid) const activeWorkspace = workspaces.find(({ id }) => id === orgId)
if (!activeWorkspace) { if (!activeWorkspace) {
const url = new URL(request.url)
const fallback = preferred_org_id const fallback = preferred_org_id
? (workspaces.find(({ id }) => id === preferred_org_id) ?? workspaces[0]) ? (workspaces.find(({ id }) => id === preferred_org_id) ?? workspaces[0])
: workspaces[0] : workspaces[0]
@@ -81,14 +88,55 @@ export const workspaceMiddleware = async (
context context
}).then((r) => r.json())) as any }).then((r) => r.json())) as any
context.set(workspaceContext, { const workspace = {
activeWorkspace, activeWorkspace,
workspaces, workspaces,
subscription: org?.['subscription'] || null, subscription: org?.['subscription'] || null,
address: org?.['address'] || null, address: org?.['address'] || null,
test_mode: 'test_mode' in org, test_mode: 'test_mode' in org,
blocked: 'subscription_frozen' in org blocked: 'subscription_frozen' in org
}) }
context.set(workspaceContext, workspace)
saveToCache(cacheKey, workspace)
return await next() return await next()
} }
function buildWorkspaceCacheKey(
request: Request,
userId: string,
orgId?: string
) {
const url = new URL(request.url)
url.pathname = `/__cache/workspace/${userId}/${orgId ?? 'none'}`
url.search = ''
return new Request(url.toString(), {
method: 'GET'
})
}
async function getFromCache(
key: Request
): Promise<WorkspaceContextProps | null> {
const cache: Cache = await caches.open('saladeaula.digital')
const cached = await cache.match(key)
if (!cached) {
return null
}
return cached.json()
}
async function saveToCache(key: Request, data: WorkspaceContextProps) {
const cache: Cache = await caches.open('saladeaula.digital')
const response = new Response(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': `public, max-age=${60 * 10}`
}
})
await cache.put(key, response)
}

View File

@@ -47,7 +47,7 @@ export async function loader({ context, request }: Route.ActionArgs) {
return { return {
user, user,
sidebar_state, sidebar_state,
...workspace workspace
} }
} }
@@ -59,7 +59,7 @@ export function shouldRevalidate({
} }
export default function Route({ loaderData }: Route.ComponentProps) { export default function Route({ loaderData }: Route.ComponentProps) {
const { user, sidebar_state, blocked, ...props } = loaderData const { user, sidebar_state, workspace } = loaderData
useEffect(() => { useEffect(() => {
if (typeof window !== 'undefined' && window.rybbit) { if (typeof window !== 'undefined' && window.rybbit) {
@@ -73,7 +73,7 @@ export default function Route({ loaderData }: Route.ComponentProps) {
return ( return (
<> <>
{blocked ? ( {workspace.blocked ? (
<AlertDialog open={true}> <AlertDialog open={true}>
<AlertDialogContent> <AlertDialogContent>
<AlertDialogTitle>Serviço com acesso suspenso</AlertDialogTitle> <AlertDialogTitle>Serviço com acesso suspenso</AlertDialogTitle>
@@ -85,10 +85,10 @@ export default function Route({ loaderData }: Route.ComponentProps) {
</AlertDialog> </AlertDialog>
) : null} ) : null}
<WorkspaceProvider {...props}> <WorkspaceProvider {...workspace}>
<SidebarProvider <SidebarProvider
defaultOpen={sidebar_state === 'true'} defaultOpen={sidebar_state === 'true'}
className={cn('flex', blocked && 'pointer-events-none')} className={cn('flex', workspace.blocked && 'pointer-events-none')}
> >
<AppSidebar /> <AppSidebar />