fix: guard tauri calls with kernel check (#5619)
This commit is contained in:
parent
7deaa136f4
commit
fdbec04703
5 changed files with 123 additions and 37 deletions
11
packages/hoppscotch-common/src/components.d.ts
vendored
11
packages/hoppscotch-common/src/components.d.ts
vendored
|
|
@ -64,10 +64,8 @@ declare module 'vue' {
|
|||
CollectionsDocumentationSectionsCurlView: typeof import('./components/collections/documentation/sections/CurlView.vue')['default']
|
||||
CollectionsDocumentationSectionsHeaders: typeof import('./components/collections/documentation/sections/Headers.vue')['default']
|
||||
CollectionsDocumentationSectionsParameters: typeof import('./components/collections/documentation/sections/Parameters.vue')['default']
|
||||
CollectionsDocumentationSectionsPreRequestScript: typeof import('./components/collections/documentation/sections/PreRequestScript.vue')['default']
|
||||
CollectionsDocumentationSectionsRequestBody: typeof import('./components/collections/documentation/sections/RequestBody.vue')['default']
|
||||
CollectionsDocumentationSectionsResponse: typeof import('./components/collections/documentation/sections/Response.vue')['default']
|
||||
CollectionsDocumentationSectionsTestScript: typeof import('./components/collections/documentation/sections/TestScript.vue')['default']
|
||||
CollectionsDocumentationSectionsVariables: typeof import('./components/collections/documentation/sections/Variables.vue')['default']
|
||||
CollectionsEdit: typeof import('./components/collections/Edit.vue')['default']
|
||||
CollectionsEditFolder: typeof import('./components/collections/EditFolder.vue')['default']
|
||||
|
|
@ -155,7 +153,6 @@ declare module 'vue' {
|
|||
HoppSmartCheckbox: typeof import('@hoppscotch/ui')['HoppSmartCheckbox']
|
||||
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal']
|
||||
HoppSmartFileChip: typeof import('@hoppscotch/ui')['HoppSmartFileChip']
|
||||
HoppSmartIcon: typeof import('@hoppscotch/ui')['HoppSmartIcon']
|
||||
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']
|
||||
HoppSmartIntersection: typeof import('@hoppscotch/ui')['HoppSmartIntersection']
|
||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
|
||||
|
|
@ -234,12 +231,10 @@ declare module 'vue' {
|
|||
IconLucideAlertTriangle: typeof import('~icons/lucide/alert-triangle')['default']
|
||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
||||
IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default']
|
||||
IconLucideBrush: typeof import('~icons/lucide/brush')['default']
|
||||
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
|
||||
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']
|
||||
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
||||
IconLucideCircleCheck: typeof import('~icons/lucide/circle-check')['default']
|
||||
IconLucideCode2: typeof import('~icons/lucide/code2')['default']
|
||||
IconLucideEyeOff: typeof import('~icons/lucide/eye-off')['default']
|
||||
IconLucideFileQuestion: typeof import('~icons/lucide/file-question')['default']
|
||||
IconLucideFileText: typeof import('~icons/lucide/file-text')['default']
|
||||
IconLucideFolder: typeof import('~icons/lucide/folder')['default']
|
||||
|
|
@ -249,13 +244,12 @@ declare module 'vue' {
|
|||
IconLucideInbox: typeof import('~icons/lucide/inbox')['default']
|
||||
IconLucideInfo: typeof import('~icons/lucide/info')['default']
|
||||
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
|
||||
IconLucideLightbulb: typeof import('~icons/lucide/lightbulb')['default']
|
||||
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
|
||||
IconLucideLoader: typeof import('~icons/lucide/loader')['default']
|
||||
IconLucideLoader2: typeof import('~icons/lucide/loader2')['default']
|
||||
IconLucideLock: typeof import('~icons/lucide/lock')['default']
|
||||
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
|
||||
IconLucidePlusCircle: typeof import('~icons/lucide/plus-circle')['default']
|
||||
IconLucideRss: typeof import('~icons/lucide/rss')['default']
|
||||
IconLucideSearch: typeof import('~icons/lucide/search')['default']
|
||||
IconLucideTerminal: typeof import('~icons/lucide/terminal')['default']
|
||||
IconLucideTriangleAlert: typeof import('~icons/lucide/triangle-alert')['default']
|
||||
|
|
@ -290,7 +284,6 @@ declare module 'vue' {
|
|||
LensesRenderersXMLLensRenderer: typeof import('./components/lenses/renderers/XMLLensRenderer.vue')['default']
|
||||
LensesResponseBodyRenderer: typeof import('./components/lenses/ResponseBodyRenderer.vue')['default']
|
||||
MockServerConfigureMockServerModal: typeof import('./components/mockServer/ConfigureMockServerModal.vue')['default']
|
||||
MockServerCreateMockServer: typeof import('./components/mockServer/CreateMockServer.vue')['default']
|
||||
MockServerCreateNewMockServerModal: typeof import('./components/mockServer/CreateNewMockServerModal.vue')['default']
|
||||
MockServerEditMockServer: typeof import('./components/mockServer/EditMockServer.vue')['default']
|
||||
MockServerLogSection: typeof import('./components/mockServer/LogSection.vue')['default']
|
||||
|
|
|
|||
|
|
@ -6,39 +6,84 @@ import type {
|
|||
} from "@hoppscotch/kernel"
|
||||
import * as E from "fp-ts/Either"
|
||||
import { getModule } from "."
|
||||
import { invoke } from "@tauri-apps/api/core"
|
||||
import { join } from "@tauri-apps/api/path"
|
||||
import { getKernelMode } from "@hoppscotch/kernel"
|
||||
|
||||
const STORE_PATH = `${window.location.host}.hoppscotch.store`
|
||||
|
||||
// These are only defined functions if in desktop mode.
|
||||
// For more context, take a look at how `hoppscotch-kernel/.../store/v1/` works
|
||||
// and how the `web` mode store kernel ignores the first file directory input.
|
||||
let invoke:
|
||||
| (<T>(cmd: string, args?: Record<string, unknown>) => Promise<T>)
|
||||
| undefined
|
||||
let join: ((...paths: string[]) => Promise<string>) | undefined
|
||||
|
||||
// Single init promise to avoid multiple imports and race conditions
|
||||
let initPromise: Promise<void> | undefined
|
||||
|
||||
const isInitd = async () => {
|
||||
if (getKernelMode() !== "desktop") return
|
||||
|
||||
if (!initPromise) {
|
||||
initPromise = Promise.all([
|
||||
import("@tauri-apps/api/core").then((module) => {
|
||||
invoke = module.invoke
|
||||
}),
|
||||
import("@tauri-apps/api/path").then((module) => {
|
||||
join = module.join
|
||||
}),
|
||||
]).then(() => {})
|
||||
}
|
||||
|
||||
await initPromise
|
||||
}
|
||||
|
||||
export const getConfigDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke) throw new Error("getConfigDir is only available in desktop mode")
|
||||
return await invoke<string>("get_config_dir")
|
||||
}
|
||||
|
||||
export const getBackupDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke) throw new Error("getBackupDir is only available in desktop mode")
|
||||
return await invoke<string>("get_backup_dir")
|
||||
}
|
||||
|
||||
export const getLatestDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke) throw new Error("getLatestDir is only available in desktop mode")
|
||||
return await invoke<string>("get_latest_dir")
|
||||
}
|
||||
|
||||
export const getStoreDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke) throw new Error("getStoreDir is only available in desktop mode")
|
||||
return await invoke<string>("get_store_dir")
|
||||
}
|
||||
|
||||
export const getInstanceDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke)
|
||||
throw new Error("getInstanceDir is only available in desktop mode")
|
||||
return await invoke<string>("get_instance_dir")
|
||||
}
|
||||
|
||||
const getStorePath = async (): Promise<string> => {
|
||||
try {
|
||||
const storeDir = await getStoreDir()
|
||||
return join(storeDir, STORE_PATH)
|
||||
} catch (error) {
|
||||
console.error("Failed to get store directory:", error)
|
||||
return "hoppscotch-unified.store"
|
||||
if (getKernelMode() === "desktop") {
|
||||
await isInitd()
|
||||
if (join) {
|
||||
try {
|
||||
const storeDir = await getStoreDir()
|
||||
return await join(storeDir, STORE_PATH)
|
||||
} catch (error) {
|
||||
console.error("Failed to get store directory:", error)
|
||||
return STORE_PATH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STORE_PATH
|
||||
}
|
||||
|
||||
export const Store = (() => {
|
||||
|
|
|
|||
|
|
@ -44,25 +44,28 @@ import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
|
|||
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
||||
import { PublishedDocs } from "~/helpers/backend/graphql"
|
||||
import { getKernelMode } from "@hoppscotch/kernel"
|
||||
import { useService } from "dioc/vue"
|
||||
import { InstanceSwitcherService } from "~/services/instance-switcher.service"
|
||||
import { platform } from "~/platform"
|
||||
import { useReadonlyStream } from "~/composables/stream"
|
||||
|
||||
const route = useRoute()
|
||||
const t = useI18n()
|
||||
|
||||
const kernelMode = getKernelMode()
|
||||
const instanceSwitcherService =
|
||||
kernelMode === "desktop" ? useService(InstanceSwitcherService) : null
|
||||
|
||||
const instancePlatform = platform.instance
|
||||
|
||||
const currentState =
|
||||
kernelMode === "desktop" && instanceSwitcherService
|
||||
kernelMode === "desktop" &&
|
||||
instancePlatform?.instanceSwitchingEnabled &&
|
||||
instancePlatform.getConnectionStateStream
|
||||
? useReadonlyStream(
|
||||
instanceSwitcherService.getStateStream(),
|
||||
instanceSwitcherService.getCurrentState().value
|
||||
instancePlatform.getConnectionStateStream(),
|
||||
instancePlatform.getCurrentConnectionState?.() ?? {
|
||||
status: "disconnected" as const,
|
||||
}
|
||||
)
|
||||
: ref({
|
||||
status: "disconnected",
|
||||
status: "disconnected" as const,
|
||||
instance: { displayName: "Hoppscotch" },
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -54,20 +54,20 @@
|
|||
<div class="flex gap-4 items-center justify-center mt-6">
|
||||
<label class="flex items-center space-x-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="portableSettings.disableUpdateNotifications"
|
||||
@change="onUpdateNotificationsChange"
|
||||
type="checkbox"
|
||||
class="form-checkbox h-4 w-4 text-accent"
|
||||
@change="onUpdateNotificationsChange"
|
||||
/>
|
||||
<span class="text-sm">Don't notify about updates</span>
|
||||
</label>
|
||||
|
||||
<label class="flex items-center space-x-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="portableSettings.autoSkipWelcome"
|
||||
@change="onAutoSkipChange"
|
||||
type="checkbox"
|
||||
class="form-checkbox h-4 w-4 text-accent"
|
||||
@change="onAutoSkipChange"
|
||||
/>
|
||||
<span class="text-sm">Don't show this again</span>
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -6,39 +6,84 @@ import type {
|
|||
} from "@hoppscotch/kernel"
|
||||
import * as E from "fp-ts/Either"
|
||||
import { getModule } from "."
|
||||
import { invoke } from "@tauri-apps/api/core"
|
||||
import { join } from "@tauri-apps/api/path"
|
||||
import { getKernelMode } from "@hoppscotch/kernel"
|
||||
|
||||
const STORE_PATH = "hoppscotch-unified.store"
|
||||
|
||||
// These are only defined functions if in desktop mode.
|
||||
// For more context, take a look at how `hoppscotch-kernel/.../store/v1/` works
|
||||
// and how the `web` mode store kernel ignores the first file directory input.
|
||||
let invoke:
|
||||
| (<T>(cmd: string, args?: Record<string, unknown>) => Promise<T>)
|
||||
| undefined
|
||||
let join: ((...paths: string[]) => Promise<string>) | undefined
|
||||
|
||||
// Single init promise to avoid multiple imports and race conditions
|
||||
let initPromise: Promise<void> | undefined
|
||||
|
||||
const isInitd = async () => {
|
||||
if (getKernelMode() !== "desktop") return
|
||||
|
||||
if (!initPromise) {
|
||||
initPromise = Promise.all([
|
||||
import("@tauri-apps/api/core").then((module) => {
|
||||
invoke = module.invoke
|
||||
}),
|
||||
import("@tauri-apps/api/path").then((module) => {
|
||||
join = module.join
|
||||
}),
|
||||
]).then(() => {})
|
||||
}
|
||||
|
||||
await initPromise
|
||||
}
|
||||
|
||||
export const getConfigDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke) throw new Error("getConfigDir is only available in desktop mode")
|
||||
return await invoke<string>("get_config_dir")
|
||||
}
|
||||
|
||||
export const getBackupDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke) throw new Error("getBackupDir is only available in desktop mode")
|
||||
return await invoke<string>("get_backup_dir")
|
||||
}
|
||||
|
||||
export const getLatestDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke) throw new Error("getLatestDir is only available in desktop mode")
|
||||
return await invoke<string>("get_latest_dir")
|
||||
}
|
||||
|
||||
export const getStoreDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke) throw new Error("getStoreDir is only available in desktop mode")
|
||||
return await invoke<string>("get_store_dir")
|
||||
}
|
||||
|
||||
export const getInstanceDir = async (): Promise<string> => {
|
||||
await isInitd()
|
||||
if (!invoke)
|
||||
throw new Error("getInstanceDir is only available in desktop mode")
|
||||
return await invoke<string>("get_instance_dir")
|
||||
}
|
||||
|
||||
const getStorePath = async (): Promise<string> => {
|
||||
try {
|
||||
const instanceDir = await getInstanceDir()
|
||||
return await join(instanceDir, STORE_PATH)
|
||||
} catch (error) {
|
||||
console.error("Failed to get instance directory:", error)
|
||||
return "hoppscotch-unified.store"
|
||||
if (getKernelMode() === "desktop") {
|
||||
await isInitd()
|
||||
if (join) {
|
||||
try {
|
||||
const instanceDir = await getInstanceDir()
|
||||
return await join(instanceDir, STORE_PATH)
|
||||
} catch (error) {
|
||||
console.error("Failed to get instance directory:", error)
|
||||
return STORE_PATH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STORE_PATH
|
||||
}
|
||||
|
||||
export const Store = (() => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue