1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.useAPQ = exports.createInMemoryAPQStore = exports.hashSHA256 = void 0;
|
4 | const graphql_1 = require("graphql");
|
5 | const tiny_lru_1 = require("tiny-lru");
|
6 | async function hashSHA256(str, api = globalThis) {
|
7 | const { crypto, TextEncoder } = api;
|
8 | const textEncoder = new TextEncoder();
|
9 | const utf8 = textEncoder.encode(str);
|
10 | const hashBuffer = await crypto.subtle.digest('SHA-256', utf8);
|
11 | let hashHex = '';
|
12 | for (const bytes of new Uint8Array(hashBuffer)) {
|
13 | hashHex += bytes.toString(16).padStart(2, '0');
|
14 | }
|
15 | return hashHex;
|
16 | }
|
17 | exports.hashSHA256 = hashSHA256;
|
18 | function createInMemoryAPQStore(options = {}) {
|
19 | return (0, tiny_lru_1.lru)(options.max ?? 1000, options.ttl ?? 36000);
|
20 | }
|
21 | exports.createInMemoryAPQStore = createInMemoryAPQStore;
|
22 | function decodeAPQExtension(input) {
|
23 | if (input != null &&
|
24 | typeof input === 'object' &&
|
25 | input?.version === 1 &&
|
26 | typeof input?.sha256Hash === 'string') {
|
27 | return input;
|
28 | }
|
29 | return null;
|
30 | }
|
31 | function useAPQ(options = {}) {
|
32 | const { store = createInMemoryAPQStore(), hash = hashSHA256 } = options;
|
33 | return {
|
34 | async onParams({ params, setParams, fetchAPI }) {
|
35 | const persistedQueryData = decodeAPQExtension(params.extensions?.persistedQuery);
|
36 | if (persistedQueryData === null) {
|
37 | return;
|
38 | }
|
39 | if (params.query == null) {
|
40 | const persistedQuery = await store.get(persistedQueryData.sha256Hash);
|
41 | if (persistedQuery == null) {
|
42 | throw new graphql_1.GraphQLError('PersistedQueryNotFound', {
|
43 | extensions: {
|
44 | http: {
|
45 | status: 404,
|
46 | },
|
47 | },
|
48 | });
|
49 | }
|
50 | setParams({
|
51 | ...params,
|
52 | query: persistedQuery,
|
53 | });
|
54 | }
|
55 | else {
|
56 | const expectedHash = await hash(params.query, fetchAPI);
|
57 | if (persistedQueryData.sha256Hash !== expectedHash) {
|
58 | throw new graphql_1.GraphQLError('PersistedQueryMismatch', {
|
59 | extensions: {
|
60 | http: {
|
61 | status: 400,
|
62 | },
|
63 | },
|
64 | });
|
65 | }
|
66 | await store.set(persistedQueryData.sha256Hash, params.query);
|
67 | }
|
68 | },
|
69 | };
|
70 | }
|
71 | exports.useAPQ = useAPQ;
|