diff options
| author | netop://ウィビ <paul@webb.page> | 2026-10-21 16:47:38 -0700 |
|---|---|---|
| committer | netop://ウィビ <paul@webb.page> | 2026-10-21 16:47:38 -0700 |
| commit | 389ad1349c4ff245a3466a2e361c1cd1dd11d2ba (patch) | |
| tree | 0ad0638f60ab0a77c7a095e96b472312ab39f83b /source/graphiql/render.ts | |
| parent | bbcbb02ef64d094f0f13de22ae135eeba1ff4c5d (diff) | |
| download | gq-389ad1349c4ff245a3466a2e361c1cd1dd11d2ba.tar.gz gq-389ad1349c4ff245a3466a2e361c1cd1dd11d2ba.zip | |
- inlined vendored dependencies from npm
- makes this module work in Ende
Diffstat (limited to '')
| -rwxr-xr-x | source/graphiql/render.ts | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/source/graphiql/render.ts b/source/graphiql/render.ts index 7adec57..c846d34 100755 --- a/source/graphiql/render.ts +++ b/source/graphiql/render.ts @@ -4,26 +4,31 @@ /*** IMPORT ------------------------------------------- ***/ import { default as dedent } from "@netopwibby/dedent"; -import { filterXSS } from "xss"; +import { GRAPHIQL_VERSION } from "./version.ts"; /*** UTILITY ------------------------------------------ ***/ -const filter = (val: string) => filterXSS(val, { - stripIgnoreTag: true, - stripIgnoreTagBody: ["script"], - whiteList: {} -}); +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 -}) => filter(`${cdnUrl}/@eeeooolll/graphiql${version ? `@${version}` : ""}/dist/${suffix}`); + cdnUrl?: string; + suffix: string; + version: string; +}) => cdnUrl ? + `${cdnUrl}/@eeeooolll/graphiql@${version}/dist/${suffix}` : + `./_graphiql/${GRAPHIQL_VERSION}/${suffix}`; /*** EXPORT ------------------------------------------- ***/ export interface RenderPageOptions { - /** Base CDN. Defaults to jsDelivr. */ + /** 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; @@ -31,7 +36,7 @@ export interface RenderPageOptions { faviconUrl?: string | null; /** Document `<title>`. */ title?: string; - /** Pin `@eeeooolll/graphiql` to a specific version on the CDN. */ + /** `@eeeooolll/graphiql` version to load from `cdnUrl`. Defaults to the embedded version; ignored when self-hosting. */ version?: string; } @@ -39,31 +44,28 @@ export interface RenderPageOptions { * Renders the GraphiQL HTML shell. * * Loads the prebuilt IIFE bundle from `@eeeooolll/graphiql` (registered as - * `window.EolGraphiQL`) and mounts it against `endpoint`. + * `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 = "//cdn.jsdelivr.net/npm", + cdnUrl, endpoint = "/graphql", faviconUrl, title = "GraphiQL", - version + version = GRAPHIQL_VERSION } = options; - const safeEndpoint = filter(endpoint); - const safeTitle = filter(title); - const scriptUrl = buildAssetUrl({ cdnUrl, suffix: "standalone.js", version }); - const styleUrl = buildAssetUrl({ cdnUrl, suffix: "standalone.css", version }); + const scriptUrl = escapeHtml(buildAssetUrl({ cdnUrl, suffix: "standalone.js", version })); + const styleUrl = escapeHtml(buildAssetUrl({ cdnUrl, suffix: "standalone.css", version })); - const faviconLink = - faviconUrl === null ? - "" : - typeof faviconUrl === "string" ? - `<link rel="shortcut icon" href="${filter(faviconUrl)}"/>` : - `<link rel="shortcut icon" href="${buildAssetUrl({ cdnUrl, suffix: "favicon.svg", version })}"/>`; + const faviconLink = faviconUrl === null ? + "" : + `<link rel="shortcut icon" href="${escapeHtml(faviconUrl ?? buildAssetUrl({ cdnUrl, suffix: "favicon.svg", version }))}"/>`; return dedent` <!DOCTYPE html> @@ -71,7 +73,7 @@ export function renderPlaygroundPage(options: RenderPageOptions): string { <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> - <title>${safeTitle}</title> + <title>${escapeHtml(title)}</title> ${faviconLink} <link rel="stylesheet" href="${styleUrl}"/> @@ -106,7 +108,7 @@ export function renderPlaygroundPage(options: RenderPageOptions): string { <script> window.addEventListener("load", () => { const root = document.getElementById("root"); - const fetcher = window.EolGraphiQL.createHttpFetcher({ url: "${safeEndpoint}" }); + const fetcher = window.EolGraphiQL.createHttpFetcher({ url: ${toScriptString(endpoint)} }); window.EolGraphiQL.mount(root, { fetcher }); }); |