aboutsummaryrefslogtreecommitdiff
path: root/source/graphiql/render.ts
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xsource/graphiql/render.ts56
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("<", "&lt;")
+ .replaceAll(">", "&gt;")
+ .replaceAll("\"", "&quot;")
+ .replaceAll("'", "&#39;");
+
+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 });
});