fix(common): extension port to relay regression (#4806)
This commit is contained in:
parent
baa1703309
commit
36d71fc127
3 changed files with 130 additions and 8 deletions
|
|
@ -39,14 +39,19 @@ import IconChrome from "~icons/brands/chrome"
|
|||
import IconFirefox from "~icons/brands/firefox"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { ExtensionInterceptorService } from "~/platform/std/interceptors/extension"
|
||||
import { computed } from "vue"
|
||||
import { useService } from "dioc/vue"
|
||||
import { ExtensionKernelInterceptorService } from "~/platform/std/kernel-interceptors/extension"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const extensionService = useService(ExtensionInterceptorService)
|
||||
const extensionService = useService(ExtensionKernelInterceptorService)
|
||||
|
||||
const extensionVersion = computed(() => {
|
||||
const versionOption = extensionService.extensionVersion
|
||||
return versionOption.value ? versionOption.value : null
|
||||
})
|
||||
|
||||
const extensionVersion = extensionService.extensionVersion
|
||||
const hasChromeExtInstalled = extensionService.chromeExtensionInstalled
|
||||
const hasFirefoxExtInstalled = extensionService.firefoxExtensionInstalled
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { computed, markRaw } from "vue"
|
||||
import { computed, markRaw, ref } from "vue"
|
||||
import { Service } from "dioc"
|
||||
import type { RelayRequest, RelayResponse } from "@hoppscotch/kernel"
|
||||
import { body } from "@hoppscotch/kernel"
|
||||
|
|
@ -14,6 +14,11 @@ import * as E from "fp-ts/Either"
|
|||
import { getI18n } from "~/modules/i18n"
|
||||
import { until } from "@vueuse/core"
|
||||
import { preProcessRelayRequest } from "~/helpers/functional/preprocess"
|
||||
import { browserIsChrome, browserIsFirefox } from "~/helpers/utils/userAgent"
|
||||
|
||||
export const cancelRunningExtensionRequest = async () => {
|
||||
window.__POSTWOMAN_EXTENSION_HOOK__?.cancelRequest()
|
||||
}
|
||||
|
||||
export class ExtensionKernelInterceptorService
|
||||
extends Service
|
||||
|
|
@ -23,8 +28,15 @@ export class ExtensionKernelInterceptorService
|
|||
private readonly store = this.bind(KernelInterceptorExtensionStore)
|
||||
|
||||
public readonly id = "extension"
|
||||
public readonly name = (t: ReturnType<typeof getI18n>) =>
|
||||
t("interceptor.extension.name")
|
||||
public readonly name = (t: ReturnType<typeof getI18n>) => {
|
||||
const version = this.extensionVersion.value
|
||||
|
||||
if (this.extensionStatus.value === "available" && version) {
|
||||
return `${t("settings.extensions")}: v${version.major}.${version.minor}`
|
||||
}
|
||||
return `${t("settings.extensions")}: ${t("settings.extension_ver_not_reported")}`
|
||||
}
|
||||
|
||||
public readonly selectable = { type: "selectable" as const }
|
||||
public readonly capabilities = {
|
||||
method: new Set([
|
||||
|
|
@ -60,19 +72,34 @@ export class ExtensionKernelInterceptorService
|
|||
} as const
|
||||
|
||||
public readonly settingsEntry = markRaw({
|
||||
title: (t: ReturnType<typeof getI18n>) =>
|
||||
t("interceptor.extension.settings_title"),
|
||||
title: (t: ReturnType<typeof getI18n>) => t("settings.extensions"),
|
||||
component: SettingsExtension,
|
||||
})
|
||||
|
||||
public readonly subtitle = markRaw(SettingsExtensionSubtitle)
|
||||
|
||||
public readonly extensionStatus = computed(
|
||||
() => this.store.getSettings().status
|
||||
)
|
||||
|
||||
public readonly extensionVersion = computed(
|
||||
() => this.store.getSettings().extensionVersion
|
||||
)
|
||||
|
||||
/**
|
||||
* Whether the extension is installed in Chrome or not.
|
||||
*/
|
||||
public readonly chromeExtensionInstalled = computed(
|
||||
() => this.extensionStatus.value === "available" && browserIsChrome()
|
||||
)
|
||||
|
||||
/**
|
||||
* Whether the extension is installed in Firefox or not.
|
||||
*/
|
||||
public readonly firefoxExtensionInstalled = computed(
|
||||
() => this.extensionStatus.value === "available" && browserIsFirefox()
|
||||
)
|
||||
|
||||
private async executeExtensionRequest(
|
||||
request: RelayRequest
|
||||
): Promise<E.Either<KernelInterceptorError, RelayResponse>> {
|
||||
|
|
@ -111,6 +138,23 @@ export class ExtensionKernelInterceptorService
|
|||
),
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
||||
if (e instanceof Error && "response" in e) {
|
||||
const response = (e as any).response
|
||||
if (response) {
|
||||
return E.right({
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: response.headers,
|
||||
body: body.body(
|
||||
response.data,
|
||||
response.headers["content-type"]
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return E.left({
|
||||
humanMessage: {
|
||||
heading: (t) => t("error.extension.heading"),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Service } from "dioc"
|
|||
import { Store } from "~/kernel/store"
|
||||
import * as E from "fp-ts/Either"
|
||||
import * as O from "fp-ts/Option"
|
||||
import { ref } from "vue"
|
||||
|
||||
const STORE_NAMESPACE = "interceptors.extension.v1"
|
||||
const SETTINGS_KEY = "settings"
|
||||
|
|
@ -13,6 +14,41 @@ export type ExtensionVersion = {
|
|||
minor: number
|
||||
}
|
||||
|
||||
export const defineSubscribableObject = <T extends object>(obj: T) => {
|
||||
const proxyObject = {
|
||||
...obj,
|
||||
_subscribers: {} as {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
[key in keyof T]?: ((...args: any[]) => any)[]
|
||||
},
|
||||
subscribe(prop: keyof T, func: (...args: any[]) => any): void {
|
||||
if (Array.isArray(this._subscribers[prop])) {
|
||||
this._subscribers[prop]?.push(func)
|
||||
} else {
|
||||
this._subscribers[prop] = [func]
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
type SubscribableProxyObject = typeof proxyObject
|
||||
|
||||
return new Proxy(proxyObject, {
|
||||
set(obj, prop, newVal) {
|
||||
obj[prop as keyof SubscribableProxyObject] = newVal
|
||||
|
||||
const currentSubscribers = obj._subscribers[prop as keyof T]
|
||||
|
||||
if (Array.isArray(currentSubscribers)) {
|
||||
for (const subscriber of currentSubscribers) {
|
||||
subscriber(newVal)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type ExtensionSettings = {
|
||||
version: "v1"
|
||||
status: ExtensionStatus
|
||||
|
|
@ -34,6 +70,7 @@ export class KernelInterceptorExtensionStore extends Service {
|
|||
public static readonly ID = "KERNEL_EXTENSION_INTERCEPTOR_STORE"
|
||||
|
||||
private settings: ExtensionSettings = { ...DEFAULT_SETTINGS }
|
||||
private extensionPollIntervalId = ref<ReturnType<typeof setInterval>>()
|
||||
|
||||
async onServiceInit(): Promise<void> {
|
||||
const initResult = await Store.init()
|
||||
|
|
@ -76,6 +113,42 @@ export class KernelInterceptorExtensionStore extends Service {
|
|||
this.updateSettings({ status })
|
||||
}
|
||||
)
|
||||
} else {
|
||||
const statusProxy = defineSubscribableObject({
|
||||
status: "waiting" as ExtensionStatus,
|
||||
})
|
||||
|
||||
window.__HOPP_EXTENSION_STATUS_PROXY__ = statusProxy
|
||||
statusProxy.subscribe(
|
||||
"status",
|
||||
(status: ExtensionStatus) => this.updateSettings({ status })
|
||||
)
|
||||
|
||||
/**
|
||||
* Keeping identifying extension backward compatible
|
||||
* We are assuming the default version is 0.24 or later. So if the extension exists, its identified immediately,
|
||||
* then we use a poll to find the version, this will get the version for 0.24 and any other version
|
||||
* of the extension, but will have a slight lag.
|
||||
* 0.24 users will get the benefits of 0.24, while the extension won't break for the old users
|
||||
*/
|
||||
this.extensionPollIntervalId.value = setInterval(() => {
|
||||
if (typeof window.__POSTWOMAN_EXTENSION_HOOK__ !== "undefined") {
|
||||
if (this.extensionPollIntervalId.value)
|
||||
clearInterval(this.extensionPollIntervalId.value)
|
||||
|
||||
const version = window.__POSTWOMAN_EXTENSION_HOOK__.getVersion()
|
||||
this.updateSettings({ extensionVersion: version })
|
||||
|
||||
// When the version is not 0.24 or higher, the extension wont do this. so we have to do it manually
|
||||
if (
|
||||
version.major === 0 &&
|
||||
version.minor <= 23 &&
|
||||
window.__HOPP_EXTENSION_STATUS_PROXY__
|
||||
) {
|
||||
window.__HOPP_EXTENSION_STATUS_PROXY__.status = "available"
|
||||
}
|
||||
}
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue