From 06ec7ba8c6dccdadebc07a2621baabdd4dfe7ebd Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 14 Sep 2023 13:21:59 +0400 Subject: [PATCH 1/3] feat: detectExtension() utility function created NOTE: it's chrome only in the moment --- src/utilities/common/detectExtension.ts | 12 ++++++++++++ src/utilities/index.ts | 1 + 2 files changed, 13 insertions(+) create mode 100644 src/utilities/common/detectExtension.ts diff --git a/src/utilities/common/detectExtension.ts b/src/utilities/common/detectExtension.ts new file mode 100644 index 00000000000..7f6b2e2fe6c --- /dev/null +++ b/src/utilities/common/detectExtension.ts @@ -0,0 +1,12 @@ +export function detectExtension(extensionId: string, callback: (status: boolean) => void) { + const img = new Image(); + img.src = `chrome-extension://${extensionId}/images/logo64.png`; + + img.onload = function () { + callback(true); + }; + + img.onerror = function () { + callback(false); + }; +} diff --git a/src/utilities/index.ts b/src/utilities/index.ts index 6462f639fea..7408b1b8ca2 100644 --- a/src/utilities/index.ts +++ b/src/utilities/index.ts @@ -120,6 +120,7 @@ export * from "./common/makeUniqueId.js"; export * from "./common/stringifyForDisplay.js"; export * from "./common/mergeOptions.js"; export * from "./common/incrementalResult.js"; +export * from "./common/detectExtension.js"; export { omitDeep } from "./common/omitDeep.js"; export { stripTypename } from "./common/stripTypename.js"; From f7390df3d10e1eda3baa0382ff5cb6e33d8867e5 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 14 Sep 2023 13:23:17 +0400 Subject: [PATCH 2/3] feat(ApolloClient): private 'EXTENSION_ID' property added --- src/core/ApolloClient.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/ApolloClient.ts b/src/core/ApolloClient.ts index 12b9e7e0e0e..a3c11f14e01 100644 --- a/src/core/ApolloClient.ts +++ b/src/core/ApolloClient.ts @@ -85,6 +85,7 @@ export class ApolloClient implements DataProxy { public defaultOptions: DefaultOptions; public readonly typeDefs: ApolloClientOptions["typeDefs"]; + private EXTENSION_ID = 'jdkknkkbebbapilgoeccciglkfbmbnfm'; private queryManager: QueryManager; private devToolsHookCb: Function; private resetStoreCallbacks: Array<() => Promise> = []; From 45489b9a425312822048cafd28860240a5bd4c09 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 14 Sep 2023 13:23:54 +0400 Subject: [PATCH 3/3] feat: checking if extension exists on chrome User Agent before logging the download message --- src/core/ApolloClient.ts | 51 ++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/core/ApolloClient.ts b/src/core/ApolloClient.ts index a3c11f14e01..fb9d6bc31bc 100644 --- a/src/core/ApolloClient.ts +++ b/src/core/ApolloClient.ts @@ -67,7 +67,7 @@ export type ApolloClientOptions = { // previously declared and exported from this module, and then reexported from // @apollo/client/core. Since we need to preserve that API anyway, the easiest // solution is to reexport mergeOptions where it was previously declared (here). -import { mergeOptions } from "../utilities/index.js"; +import { mergeOptions, detectExtension } from "../utilities/index.js"; export { mergeOptions }; /** @@ -254,34 +254,49 @@ export class ApolloClient implements DataProxy { if ( typeof window !== "undefined" && window.document && - window.top === window.self && - !(window as any).__APOLLO_DEVTOOLS_GLOBAL_HOOK__ + window.top === window.self ) { const nav = window.navigator; const ua = nav && nav.userAgent; + const userAgentExists = typeof ua === 'string'; + const isChromeAgent = userAgentExists && ua.indexOf("Chrome/") > -1; + const isFirefoxAgent = userAgentExists && ua.indexOf("Chrome/") > -1; let url: string | undefined; - if (typeof ua === "string") { - if (ua.indexOf("Chrome/") > -1) { - url = - "https://chrome.google.com/webstore/detail/" + - "apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm"; - } else if (ua.indexOf("Firefox/") > -1) { - url = - "https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/"; - } + + if (isChromeAgent) { + url = + "https://chrome.google.com/webstore/detail/" + + `apollo-client-developer-t/${this.EXTENSION_ID}`; + } else if (isFirefoxAgent) { + url = + "https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/"; + } + + if (isFirefoxAgent && url) { + this.logExtensionDownloadMessage(url); + return; } - if (url) { - invariant.log( - "Download the Apollo DevTools for a better development " + - "experience: %s", - url - ); + + if (isChromeAgent) { + detectExtension(this.EXTENSION_ID, (isInstalled) => { + if (!isInstalled && url) { + this.logExtensionDownloadMessage(url); + } + }); } } }, 10000); } } + private logExtensionDownloadMessage(url: string) { + invariant.log( + "Download the Apollo DevTools for a better development " + + "experience: %s", + url + ); + } + /** * The `DocumentTransform` used to modify GraphQL documents before a request * is made. If a custom `DocumentTransform` is not provided, this will be the