/*** IMPORT ------------------------------------------- ***/ import { default as dedent } from "@netopwibby/dedent"; import { GRAPHIQL_VERSION } from "./version.ts"; /*** UTILITY ------------------------------------------ ***/ const escapeHtml = (value: string) => value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll("\"", """) .replaceAll("'", "'"); const toScriptString = (value: string) => JSON.stringify(value).replaceAll("<", "\\u003c"); const buildAssetUrl = ({ cdnUrl, suffix, version }: { cdnUrl?: string; suffix: string; version: string; }) => cdnUrl ? `${cdnUrl}/@eeeooolll/graphiql@${version}/dist/${suffix}` : `./_graphiql/${GRAPHIQL_VERSION}/${suffix}`; /*** EXPORT ------------------------------------------- ***/ export interface RenderPageOptions { /** Load the bundle from this CDN base (e.g. `//cdn.jsdelivr.net/npm`) instead of the copy embedded in gq. */ cdnUrl?: string; /** GraphQL endpoint the embedded fetcher posts to. */ endpoint?: string; /** Optional ``. `null` skips, `undefined` falls back to default. */ faviconUrl?: string | null; /** Document ``. */ title?: string; /** `@eeeooolll/graphiql` version to load from `cdnUrl`. Defaults to the embedded version; ignored when self-hosting. */ version?: string; } /** * Renders the GraphiQL HTML shell. * * Loads the prebuilt IIFE bundle from `@eeeooolll/graphiql` (registered as * `window.EolGraphiQL`) and mounts it against `endpoint`. The bundle is * embedded in gq and served by `GraphQLHTTP`; set `cdnUrl` to load it * from a CDN instead. * * Usually called indirectly via `GraphQLHTTP({ graphiql: true })`; invoke it * directly if you need to embed GraphiQL in a custom route. */ export function renderPlaygroundPage(options: RenderPageOptions): string { const { cdnUrl, endpoint = "/graphql", faviconUrl, title = "GraphiQL", version = GRAPHIQL_VERSION } = options; const scriptUrl = escapeHtml(buildAssetUrl({ cdnUrl, suffix: "standalone.js", version })); const styleUrl = escapeHtml(buildAssetUrl({ cdnUrl, suffix: "standalone.css", version })); const faviconLink = faviconUrl === null ? "" : `<link rel="shortcut icon" href="${escapeHtml(faviconUrl ?? buildAssetUrl({ cdnUrl, suffix: "favicon.svg", version }))}"/>`; return dedent` <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>${escapeHtml(title)} ${faviconLink}
`; }