Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore(persisted): Refactor sha256 utilities and persistedFetchExchange (#3052)

authored by

Phil Pluckthun and committed by
GitHub
8deee397 afc68a18

+70 -68
+5
.changeset/brave-sloths-bathe.md
··· 1 + --- 2 + '@urql/exchange-persisted-fetch': patch 3 + --- 4 + 5 + Refactor `persistedFetchExchange` and SHA256 logic to save on bundlesize.
+36 -31
exchanges/persisted-fetch/src/persistedFetchExchange.ts
··· 86 86 // Attach SHA256 hash and remove query from body 87 87 body.query = undefined; 88 88 body.extensions = { 89 + ...body.extensions, 89 90 persistedQuery: { 90 91 version: 1, 91 92 sha256Hash, ··· 108 109 if (result.error && isPersistedUnsupported(result.error)) { 109 110 // Reset the body back to its non-persisted state 110 111 body.query = query; 111 - body.extensions = undefined; 112 + if (body.extensions && body.extensions.persistedQuery) 113 + body.extensions.persistedQuery = undefined; 112 114 // Disable future persisted queries if they're not enforced 113 115 supportsPersistedQueries = false; 114 116 return makePersistedFetchSource( ··· 154 156 ): Source<OperationResult> => { 155 157 const newOperation = makeOperation(operation.kind, operation, { 156 158 ...operation.context, 157 - preferGetMethod: useGet || operation.context.preferGetMethod, 159 + preferGetMethod: useGet ? 'force' : operation.context.preferGetMethod, 158 160 }); 159 161 160 - const url = makeFetchURL( 161 - newOperation, 162 - body.query ? body : { ...body, query: '' } 163 - ); 164 - 162 + const url = makeFetchURL(newOperation, body); 165 163 const fetchOptions = makeFetchOptions(newOperation, body); 166 164 167 165 dispatchDebug({ ··· 176 174 }, 177 175 }); 178 176 179 - return pipe( 180 - makeFetchSource(newOperation, url, fetchOptions), 181 - onPush(result => { 182 - const persistFail = 183 - result.error && 184 - (isPersistedMiss(result.error) || isPersistedUnsupported(result.error)); 185 - const error = !result.data ? result.error : undefined; 177 + let fetch$ = makeFetchSource(newOperation, url, fetchOptions); 178 + 179 + if (process.env.NODE_ENV !== 'production') { 180 + fetch$ = pipe( 181 + fetch$, 182 + onPush(result => { 183 + const persistFail = 184 + result.error && 185 + (isPersistedMiss(result.error) || 186 + isPersistedUnsupported(result.error)); 187 + const error = !result.data ? result.error : undefined; 188 + 189 + dispatchDebug({ 190 + // TODO: Assign a new name to this once @urql/devtools supports it 191 + type: persistFail || error ? 'fetchError' : 'fetchSuccess', 192 + message: persistFail 193 + ? 'A Persisted Query request has failed. A non-persisted GraphQL request will follow.' 194 + : `A ${ 195 + error ? 'failed' : 'successful' 196 + } fetch response has been returned.`, 197 + operation, 198 + data: { 199 + url, 200 + fetchOptions, 201 + value: persistFail ? result.error! : error || result, 202 + }, 203 + }); 204 + }) 205 + ); 206 + } 186 207 187 - dispatchDebug({ 188 - // TODO: Assign a new name to this once @urql/devtools supports it 189 - type: persistFail || error ? 'fetchError' : 'fetchSuccess', 190 - message: persistFail 191 - ? 'A Persisted Query request has failed. A non-persisted GraphQL request will follow.' 192 - : `A ${ 193 - error ? 'failed' : 'successful' 194 - } fetch response has been returned.`, 195 - operation, 196 - data: { 197 - url, 198 - fetchOptions, 199 - value: persistFail ? result.error! : error || result, 200 - }, 201 - }); 202 - }) 203 - ); 208 + return fetch$; 204 209 }; 205 210 206 211 const isPersistedMiss = (error: CombinedError): boolean =>
+29 -37
exchanges/persisted-fetch/src/sha256.ts
··· 1 - const globals: { crypto?: Crypto } = (typeof window !== 'undefined' 2 - ? window 1 + const webCrypto = (typeof window !== 'undefined' 2 + ? window.crypto 3 3 : typeof self !== 'undefined' 4 - ? self 5 - : null) as any; 6 - const webCrypto = globals && globals.crypto; 4 + ? self.crypto 5 + : null) as typeof globalThis.crypto | null; 7 6 8 - const sha256Browser = (bytes: Uint8Array): Promise<Uint8Array> => 9 - webCrypto!.subtle 10 - .digest({ name: 'SHA-256' }, bytes) 11 - .then(result => new Uint8Array(result)); 7 + let nodeCrypto: Promise<typeof import('crypto') | void> | void; 12 8 13 - let nodeCrypto: Promise<typeof import('crypto')> | void; 14 - if (typeof window === 'undefined' && !webCrypto) { 15 - // Indirect eval'd require/import to guarantee no side-effects in module scope 16 - // (optimization for minifiers) 17 - try { 18 - nodeCrypto = Promise.resolve( 19 - new Function('require', 'return require("crypto")')(require) 20 - ); 21 - } catch (_error) { 9 + const getNodeCrypto = async (): Promise<typeof import('crypto') | void> => { 10 + if (!nodeCrypto) { 11 + // Indirect eval'd require/import to guarantee no side-effects in module scope 12 + // (optimization for minifiers) 22 13 try { 23 - nodeCrypto = new Function('return import("crypto")')(); 24 - } catch (_error) {} 14 + nodeCrypto = new Function('require', 'return require("crypto")')(require); 15 + } catch (_error) { 16 + try { 17 + nodeCrypto = new Function('return import("crypto")')(); 18 + } catch (_error) {} 19 + } 25 20 } 26 - } 21 + return nodeCrypto; 22 + }; 27 23 28 24 export const hash = async (query: string): Promise<string> => { 29 - // Node.js support 30 - if (nodeCrypto) { 31 - return nodeCrypto.then(crypto => 32 - crypto.createHash('sha256').update(query).digest('hex') 25 + if (webCrypto) { 26 + const digest = await webCrypto.subtle.digest( 27 + { name: 'SHA-256' }, 28 + new TextEncoder().encode(query) 29 + ); 30 + return new Uint8Array(digest).reduce( 31 + (prev, byte) => prev + byte.toString(16).padStart(2, '0'), 32 + '' 33 33 ); 34 - } else if (webCrypto) { 35 - const buf = new TextEncoder().encode(query); 36 - const out = await sha256Browser(buf); 37 - 38 - let hash = ''; 39 - for (let i = 0, l = out.length; i < l; i++) { 40 - const hex = out[i].toString(16); 41 - hash += '00'.slice(0, Math.max(0, 2 - hex.length)) + hex; 42 - } 43 - 44 - return hash; 34 + } else if (await getNodeCrypto()) { 35 + // Node.js support 36 + return (await nodeCrypto)!.createHash('sha256').update(query).digest('hex'); 45 37 } 46 38 47 39 if (process.env.NODE_ENV !== 'production') { ··· 51 43 ); 52 44 } 53 45 54 - return Promise.resolve(''); 46 + return ''; 55 47 };