Files
neuf-www/web/src/app/client.ts
T
2026-10-13 23:59:14 +02:00

72 lines
2.3 KiB
TypeScript

import "server-only";
import {
type AnyVariables,
type TypedDocumentNode,
cacheExchange,
createClient,
fetchExchange,
stringifyDocument,
} from "@urql/core";
import { registerUrql } from "@urql/next/rsc";
import { cmsCache, cmsCacheForToday } from "@/lib/cmsCache";
const wagtailBaseUrl = process.env.WAGTAIL_BASE_URL;
if (!wagtailBaseUrl) {
throw new Error("WAGTAIL_BASE_URL is not set");
}
const graphqlEndpoint = `${wagtailBaseUrl.replace(/\/$/, "")}/api/graphql/`;
const makeClient = () => {
return createClient({
url: graphqlEndpoint,
exchanges: [cacheExchange, fetchExchange],
});
};
// Uncached. Only for per-user (search) and token-scoped (preview) queries,
// together with the `uncached` context; everything else goes through cmsQuery
export const { getClient } = registerUrql(makeClient);
// Throws on GraphQL and network errors, which keeps them out of the cache
async function runQuery(query: string, variables: AnyVariables) {
const { data, error } = await getClient().query(query, variables);
if (error) throw new Error(error.message);
return data;
}
// The cached functions take the query as text: their arguments are the cache
// key, and urql adds bookkeeping properties to document objects it has seen
async function cachedQuery(query: string, variables: AnyVariables) {
"use cache";
cmsCache();
return runQuery(query, variables);
}
async function cachedQueryForToday(query: string, variables: AnyVariables) {
"use cache";
cmsCacheForToday();
return runQuery(query, variables);
}
// Every cacheable CMS read goes through one of the two functions below, so
// all of them carry the tag the CMS webhook purges
// Cached until the content is edited in the CMS
export function cmsQuery<Data, Variables extends AnyVariables>(
document: TypedDocumentNode<Data, Variables>,
variables: Variables
): Promise<Data | undefined> {
return cachedQuery(stringifyDocument(document), variables);
}
// For queries where the CMS decides by today's date what to return
// (futureEvents): also purged at Oslo midnight
export function cmsQueryForToday<Data, Variables extends AnyVariables>(
document: TypedDocumentNode<Data, Variables>,
variables: Variables
): Promise<Data | undefined> {
return cachedQueryForToday(stringifyDocument(document), variables);
}