UNPKG

@graphql-yoga/plugin-apq

Version:
58 lines (56 loc) 2.43 kB
let graphql_yoga = require("graphql-yoga"); let _whatwg_node_promise_helpers = require("@whatwg-node/promise-helpers"); //#region src/index.ts function hashSHA256(text, api = globalThis) { const inputUint8Array = new api.TextEncoder().encode(text); return (0, _whatwg_node_promise_helpers.handleMaybePromise)(() => api.crypto.subtle.digest({ name: "SHA-256" }, inputUint8Array), (arrayBuf) => { const outputUint8Array = new Uint8Array(arrayBuf); let hash = ""; for (const byte of outputUint8Array) { const hex = byte.toString(16); hash += "00".slice(0, Math.max(0, 2 - hex.length)) + hex; } return hash; }); } function createInMemoryAPQStore(options = {}) { return (0, graphql_yoga.createLRUCache)({ max: options.max ?? 1e3, ttl: options.ttl ?? 36e3 }); } function isAPQExtension(input) { return input != null && typeof input === "object" && "version" in input && input?.version === 1 && "sha256Hash" in input && typeof input?.sha256Hash === "string"; } function decodeAPQExtension(input) { if (isAPQExtension(input)) return input; return null; } function useAPQ(options = {}) { const { store = createInMemoryAPQStore(), hash = hashSHA256, responseConfig = {} } = options; return { onParams({ params, setParams, fetchAPI }) { const persistedQueryData = decodeAPQExtension(params.extensions?.["persistedQuery"]); if (persistedQueryData === null) return; if (params.query == null) return (0, _whatwg_node_promise_helpers.handleMaybePromise)(() => store.get(persistedQueryData.sha256Hash), (persistedQuery) => { if (persistedQuery == null) throw (0, graphql_yoga.createGraphQLError)("PersistedQueryNotFound", { extensions: { http: { status: responseConfig.forceStatusCodeOk ? 200 : 404 }, code: "PERSISTED_QUERY_NOT_FOUND" } }); setParams({ ...params, query: persistedQuery }); }); return (0, _whatwg_node_promise_helpers.handleMaybePromise)(() => hash(params.query, fetchAPI), (expectedHash) => { if (persistedQueryData.sha256Hash !== expectedHash) throw (0, graphql_yoga.createGraphQLError)("PersistedQueryMismatch", { extensions: { http: { status: responseConfig.forceStatusCodeOk ? 200 : 400 }, code: "PERSISTED_QUERY_MISMATCH" } }); return store.set(persistedQueryData.sha256Hash, params.query); }); } }; } //#endregion exports.createInMemoryAPQStore = createInMemoryAPQStore; exports.hashSHA256 = hashSHA256; exports.useAPQ = useAPQ;