Files
matrix-authentication-service/frontend/src/graphql.ts
T
Quentin Gliech a1bfbb6cdd Read the entrypoint configuration from data attributes
Instead of injecting configuration through inline <script> tags setting
window globals, server-rendered templates now carry the configuration
as data attributes on the entrypoint mount node, validated client-side
with a valibot schema over element.dataset. This removes all inline
scripts from the templates, which is friendlier to CSP, and gives the
frontend runtime-validated, typed configuration.

The DOM read and the wiring now happen in the entrypoints themselves:
main.tsx parses the mount node dataset, owns the QueryClient, and
injects the basepath and GraphQL endpoint into the router and request
layer instead of those being module-scope singletons.
2026-07-30 20:51:01 +02:00

75 lines
2.0 KiB
TypeScript

// Copyright 2025, 2026 Element Creations Ltd.
// Copyright 2024, 2025 New Vector Ltd.
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
import type { ExecutionResult } from "graphql";
import type { TypedDocumentString } from "./gql/graphql";
let graphqlEndpoint = "/graphql";
/**
* Sets the GraphQL endpoint to use for requests.
* This is called during initialization, once config has been loaded.
*/
export const setGraphqlEndpoint = (endpoint: string): void => {
graphqlEndpoint = endpoint;
};
type RequestOptions<TData, TVariables> = {
query: TypedDocumentString<TData, TVariables>;
signal?: AbortSignal;
// biome-ignore lint/suspicious/noExplicitAny: this is for inference
} & (TVariables extends Record<any, never>
? { variables?: TVariables }
: { variables: TVariables });
export const graphqlRequest = async <TData, TVariables>({
query,
variables,
signal,
}: RequestOptions<TData, TVariables>): Promise<TData> => {
const endpoint =
import.meta.env.TEST && typeof window === "undefined"
? new URL(graphqlEndpoint, "http://localhost/").toString()
: new URL(graphqlEndpoint, window.location.toString()).toString();
let response: Response;
try {
response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query,
variables,
}),
signal,
});
} catch (cause) {
throw new Error(`GraphQL request to ${endpoint} request failed`, {
cause,
});
}
if (!response.ok) {
throw new Error(
`GraphQL request to ${endpoint} failed: ${response.status}`,
);
}
const json: ExecutionResult<TData> = await response.json();
if (json.errors) {
throw new Error(JSON.stringify(json.errors));
}
if (!json.data) {
throw new Error(`GraphQL request to ${endpoint} returned no data`);
}
return json.data;
};