@graphql-yoga/plugin-apq
Version:
APQ plugin for GraphQL Yoga.
60 lines (59 loc) • 2.26 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useAPQ = exports.createInMemoryAPQStore = exports.hashSHA256 = void 0;
const graphql_1 = require("graphql");
const tiny_lru_1 = require("tiny-lru");
const fetch_1 = require("@whatwg-node/fetch");
const textEncoder = new fetch_1.TextEncoder();
async function hashSHA256(str) {
const utf8 = textEncoder.encode(str);
const hashBuffer = await fetch_1.crypto.subtle.digest('SHA-256', utf8);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray
.map((bytes) => bytes.toString(16).padStart(2, '0'))
.join('');
return hashHex;
}
exports.hashSHA256 = hashSHA256;
function createInMemoryAPQStore(options = {}) {
return (0, tiny_lru_1.lru)(options.max ?? 1000, options.ttl ?? 36000);
}
exports.createInMemoryAPQStore = createInMemoryAPQStore;
function decodeAPQExtension(input) {
if (input != null &&
typeof input === 'object' &&
input?.version === 1 &&
typeof input?.sha256Hash === 'string') {
return input;
}
return null;
}
function useAPQ(options = {}) {
const { store = createInMemoryAPQStore(), hash = hashSHA256 } = options;
return {
async onParams({ params, setParams }) {
const persistedQueryData = decodeAPQExtension(params.extensions?.persistedQuery);
if (persistedQueryData === null) {
return;
}
if (params.query == null) {
const persistedQuery = await store.get(persistedQueryData.sha256Hash);
if (persistedQuery == null) {
throw new graphql_1.GraphQLError('PersistedQueryNotFound');
}
setParams({
...params,
query: persistedQuery,
});
}
else {
const expectedHash = await hash(params.query);
if (persistedQueryData.sha256Hash !== expectedHash) {
throw new graphql_1.GraphQLError('PersistedQueryMismatch');
}
await store.set(persistedQueryData.sha256Hash, params.query);
}
},
};
}
exports.useAPQ = useAPQ;