From 389ad1349c4ff245a3466a2e361c1cd1dd11d2ba Mon Sep 17 00:00:00 2001 From: "netop://ウィビ" Date: Wed, 21 Oct 2026 16:47:38 -0700 Subject: MAJOR RELEASE - inlined vendored dependencies from npm - makes this module work in Ende --- deno.json | 16 - deno.lock | 122 - ende.json | 21 + entry.ts | 9 +- source/common.ts | 2 +- source/gql.ts | 3 +- source/graphiql/assets.ts | 28 + source/graphiql/favicon.svg | 15 + source/graphiql/render.ts | 56 +- source/graphiql/standalone.css | 2 + source/graphiql/standalone.js | 207 + source/graphiql/version.ts | 1 + source/http.ts | 10 +- source/import.ts | 2 +- source/utility/pubsub.ts | 64 + source/utility/types.ts | 2 +- source/ws.ts | 4 +- vendor/deps.d.ts | 14536 +++++++++++++++++++++++++++++++++++++++ vendor/deps.js | 190 + vendor/deps.ts | 5 + vendor/package.json | 16 + vendor/tsconfig.json | 12 + 22 files changed, 15147 insertions(+), 176 deletions(-) delete mode 100644 deno.json delete mode 100644 deno.lock create mode 100644 ende.json create mode 100644 source/graphiql/assets.ts create mode 100644 source/graphiql/favicon.svg create mode 100644 source/graphiql/standalone.css create mode 100644 source/graphiql/standalone.js create mode 100644 source/graphiql/version.ts create mode 100644 source/utility/pubsub.ts create mode 100644 vendor/deps.d.ts create mode 100644 vendor/deps.js create mode 100644 vendor/deps.ts create mode 100644 vendor/package.json create mode 100644 vendor/tsconfig.json diff --git a/deno.json b/deno.json deleted file mode 100644 index bddf2d3..0000000 --- a/deno.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "exports": "./entry.ts", - "imports": { - "@eeeooolll/graphiql": "npm:@eeeooolll/graphiql@0.4.2", - "@graphql-tools/schema": "npm:@graphql-tools/schema@^10.0.33", - "@netopwibby/dedent": "jsr:@netopwibby/dedent@^0.1.0", - "@std/path": "jsr:@std/path@^1.1.4", - "graphql": "npm:graphql@^16.13.2", - "graphql-subscriptions": "npm:graphql-subscriptions@^2.0.0", - "graphql-ws": "npm:graphql-ws@^5.16.0", - "xss": "npm:xss@^1.0.15" - }, - "license": "MIT", - "name": "@eol/gq", - "version": "0.6.1" -} diff --git a/deno.lock b/deno.lock deleted file mode 100644 index ebfe5b7..0000000 --- a/deno.lock +++ /dev/null @@ -1,122 +0,0 @@ -{ - "version": "5", - "specifiers": { - "jsr:@netopwibby/dedent@0.1": "0.1.0", - "jsr:@std/internal@^1.0.12": "1.0.13", - "jsr:@std/path@^1.1.4": "1.1.4", - "npm:@graphql-tools/schema@^10.0.33": "10.0.33_graphql@16.13.2", - "npm:graphql-subscriptions@2": "2.0.0_graphql@16.13.2", - "npm:graphql-ws@^5.16.0": "5.16.2_graphql@16.13.2", - "npm:graphql@^16.13.2": "16.13.2", - "npm:xss@^1.0.15": "1.0.15" - }, - "jsr": { - "@netopwibby/dedent@0.1.0": { - "integrity": "fcd8ffe607efdbe11ddcefa9169935514744b6b064ed634390818227fa0b401e" - }, - "@std/internal@1.0.13": { - "integrity": "2f9546691d4ac2d32859c82dff284aaeac980ddeca38430d07941e7e288725c0" - }, - "@std/path@1.1.4": { - "integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5", - "dependencies": [ - "jsr:@std/internal" - ] - } - }, - "npm": { - "@graphql-tools/merge@9.1.9_graphql@16.13.2": { - "integrity": "sha512-iHUWNjRHeQRYdgIMIuChThOwoKzA9vrzYeslgfBo5eUYEyHGZCoDPjAavssoYXLwstYt1dZj2J22jSzc2DrN0Q==", - "dependencies": [ - "@graphql-tools/utils", - "graphql", - "tslib" - ] - }, - "@graphql-tools/schema@10.0.33_graphql@16.13.2": { - "integrity": "sha512-O6P3RIftO0jafnSsFAqpjurUuUxJ43s/AdPVLQsBkI6y4Ic/tKm4C1Qm1KKQsCDTOxXPJClh/v3g7k7yLKCFBQ==", - "dependencies": [ - "@graphql-tools/merge", - "@graphql-tools/utils", - "graphql", - "tslib" - ] - }, - "@graphql-tools/utils@11.1.0_graphql@16.13.2": { - "integrity": "sha512-PtFVG4r8Z2LEBSaPYQMusBiB3o6kjLVJyjCLbnWem/SpSuM21v6LTmgpkXfYU1qpBV2UGsFyuEnSJInl8fR1Ag==", - "dependencies": [ - "@graphql-typed-document-node/core", - "@whatwg-node/promise-helpers", - "cross-inspect", - "graphql", - "tslib" - ] - }, - "@graphql-typed-document-node/core@3.2.0_graphql@16.13.2": { - "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", - "dependencies": [ - "graphql" - ] - }, - "@whatwg-node/promise-helpers@1.3.2": { - "integrity": "sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA==", - "dependencies": [ - "tslib" - ] - }, - "commander@2.20.3": { - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "cross-inspect@1.0.1": { - "integrity": "sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A==", - "dependencies": [ - "tslib" - ] - }, - "cssfilter@0.0.10": { - "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==" - }, - "graphql-subscriptions@2.0.0_graphql@16.13.2": { - "integrity": "sha512-s6k2b8mmt9gF9pEfkxsaO1lTxaySfKoEJzEfmwguBbQ//Oq23hIXCfR1hm4kdh5hnR20RdwB+s3BCb+0duHSZA==", - "dependencies": [ - "graphql", - "iterall" - ] - }, - "graphql-ws@5.16.2_graphql@16.13.2": { - "integrity": "sha512-E1uccsZxt/96jH/OwmLPuXMACILs76pKF2i3W861LpKBCYtGIyPQGtWLuBLkND4ox1KHns70e83PS4te50nvPQ==", - "dependencies": [ - "graphql" - ] - }, - "graphql@16.13.2": { - "integrity": "sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==" - }, - "iterall@1.3.0": { - "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" - }, - "tslib@2.8.1": { - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, - "xss@1.0.15": { - "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==", - "dependencies": [ - "commander", - "cssfilter" - ], - "bin": true - } - }, - "workspace": { - "dependencies": [ - "jsr:@netopwibby/dedent@0.1", - "jsr:@std/path@^1.1.4", - "npm:@eeeooolll/graphiql@0.4.2", - "npm:@graphql-tools/schema@^10.0.33", - "npm:graphql-subscriptions@2", - "npm:graphql-ws@^5.16.0", - "npm:graphql@^16.13.2", - "npm:xss@^1.0.15" - ] - } -} diff --git a/ende.json b/ende.json new file mode 100644 index 0000000..59f5661 --- /dev/null +++ b/ende.json @@ -0,0 +1,21 @@ +{ + "exclude": [ + "vendor/" + ], + "exports": "./entry.ts", + "imports": { + "@ende/path": "jsr:@ende/path@^2026.10.15", + "@netopwibby/dedent": "jsr:@netopwibby/dedent@^0.1.0", + "#deps": "./vendor/deps.js" + }, + "license": "MIT", + "name": "@eol/gq", + "publish": { + "exclude": [ + "!vendor/", + "Icon*", + "**/Icon*" + ] + }, + "version": "0.7.0" +} diff --git a/entry.ts b/entry.ts index 6c43287..0ab9b1f 100755 --- a/entry.ts +++ b/entry.ts @@ -7,10 +7,10 @@ export * from "./source/common.ts"; export * from "./source/http.ts"; export * from "./source/ws.ts"; -export { makeExecutableSchema as executeSchema } from "@graphql-tools/schema"; +export { makeExecutableSchema as executeSchema } from "#deps"; export { gql } from "./source/gql.ts"; export { importQL } from "./source/import.ts"; -export { PubSub } from "graphql-subscriptions"; +export { PubSub } from "./source/utility/pubsub.ts"; export type { DocumentNode, @@ -22,6 +22,7 @@ export type { GraphQLSchema, GraphQLTypeResolver, Source -} from "graphql"; +} from "#deps"; -export type { PubSubEngine } from "graphql-subscriptions"; +// @ts-ignore: TS2305 +export type { PubSubEngine } from "#deps"; diff --git a/source/common.ts b/source/common.ts index 902bdd0..777bb98 100755 --- a/source/common.ts +++ b/source/common.ts @@ -3,7 +3,7 @@ /*** IMPORT ------------------------------------------- ***/ -import { graphql, type ExecutionResult } from "graphql"; +import { graphql, type ExecutionResult } from "#deps"; /*** UTILITY ------------------------------------------ ***/ diff --git a/source/gql.ts b/source/gql.ts index f88d8ff..823f73a 100644 --- a/source/gql.ts +++ b/source/gql.ts @@ -8,7 +8,7 @@ import { type DefinitionNode, type DocumentNode, type Location -} from "graphql"; +} from "#deps"; /*** UTILITY ------------------------------------------ ***/ @@ -143,6 +143,7 @@ function parseDocument(source: string) { const cacheKey = normalize(source); if (!docCache.has(cacheKey)) { + // @ts-ignore: TS2353 const parsed = parse(source, { allowLegacyFragmentVariables }); if (!parsed || parsed.kind !== "Document") diff --git a/source/graphiql/assets.ts b/source/graphiql/assets.ts new file mode 100644 index 0000000..d0848e7 --- /dev/null +++ b/source/graphiql/assets.ts @@ -0,0 +1,28 @@ +// source/graphiql/assets.ts +import css from "./standalone.css" with { type: "text" }; +import favicon from "./favicon.svg" with { type: "text" }; +import js from "./standalone.js" with { type: "text" }; +import { GRAPHIQL_VERSION } from "./version.ts"; + +const base = `/_graphiql/${GRAPHIQL_VERSION}`; + +export const assets: Record = { + [`${base}/favicon.svg`]: { body: favicon, type: "image/svg+xml" }, + [`${base}/standalone.css`]: { body: css, type: "text/css; charset=utf-8" }, + [`${base}/standalone.js`]: { body: js, type: "text/javascript; charset=utf-8" } +}; + +export function serveAsset(request: { url: string }): Response | undefined { + const { pathname } = new URL(request.url); + const key = Object.keys(assets).find((path) => pathname.endsWith(path)); + + if (!key) + return; + + return new Response(assets[key].body, { + headers: { + "cache-control": "public, max-age=31536000, immutable", + "content-type": assets[key].type + } + }); +} diff --git a/source/graphiql/favicon.svg b/source/graphiql/favicon.svg new file mode 100644 index 0000000..80a7a21 --- /dev/null +++ b/source/graphiql/favicon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + 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?: 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} + ${escapeHtml(title)} ${faviconLink} @@ -106,7 +108,7 @@ export function renderPlaygroundPage(options: RenderPageOptions): string {