@graphql-yoga/plugin-apq
Version:
APQ plugin for GraphQL Yoga.
82 lines (81 loc) • 3.31 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashSHA256 = hashSHA256;
exports.createInMemoryAPQStore = createInMemoryAPQStore;
exports.useAPQ = useAPQ;
const graphql_yoga_1 = require("graphql-yoga");
const promise_helpers_1 = require("@whatwg-node/promise-helpers");
function hashSHA256(text, api = globalThis) {
const inputUint8Array = new api.TextEncoder().encode(text);
return (0, promise_helpers_1.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_1.createLRUCache)({
max: options.max ?? 1000,
ttl: options.ttl ?? 36_000,
});
}
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, promise_helpers_1.handleMaybePromise)(() => store.get(persistedQueryData.sha256Hash), persistedQuery => {
if (persistedQuery == null) {
throw (0, graphql_yoga_1.createGraphQLError)('PersistedQueryNotFound', {
extensions: {
http: {
status: responseConfig.forceStatusCodeOk ? 200 : 404,
},
code: 'PERSISTED_QUERY_NOT_FOUND',
},
});
}
setParams({
...params,
query: persistedQuery,
});
});
}
return (0, promise_helpers_1.handleMaybePromise)(() => hash(params.query, fetchAPI), expectedHash => {
if (persistedQueryData.sha256Hash !== expectedHash) {
throw (0, graphql_yoga_1.createGraphQLError)('PersistedQueryMismatch', {
extensions: {
http: {
status: responseConfig.forceStatusCodeOk ? 200 : 400,
},
code: 'PERSISTED_QUERY_MISMATCH',
},
});
}
return store.set(persistedQueryData.sha256Hash, params.query);
});
},
};
}
;