diff --git a/packages/devtools/client/components/AssetDetails.vue b/packages/devtools/client/components/AssetDetails.vue
index edf5f17d6c..f45b85f98d 100644
--- a/packages/devtools/client/components/AssetDetails.vue
+++ b/packages/devtools/client/components/AssetDetails.vue
@@ -4,7 +4,7 @@ import { computedAsync, useTimeAgo, useVModel } from '@vueuse/core'
import { computed, ref } from 'vue'
import { devtoolsUiShowNotification } from '#imports'
import { useCopy, useOpenInEditor } from '~/composables/editor'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
import { useServerConfig } from '~/composables/state'
const props = defineProps<{
@@ -17,7 +17,7 @@ const asset = useVModel(props, 'modelValue', emit, { passive: true })
const imageMeta = computedAsync(async () => {
if (asset.value.type !== 'image')
return undefined
- return rpc.getImageMeta(asset.value.filePath)
+ return (await useDevtoolsRpc()).call('getImageMeta', asset.value.filePath)
})
const editDialog = ref(false)
@@ -30,7 +30,7 @@ const textContent = computedAsync(async () => {
// eslint-disable-next-line ts/no-unused-expressions
textContentCounter.value
- const content = await rpc.getTextAssetContent(asset.value.filePath)
+ const content = await (await useDevtoolsRpc()).call('getTextAssetContent', asset.value.filePath)
newTextContent.value = content
return content
})
@@ -38,7 +38,7 @@ const textContent = computedAsync(async () => {
async function saveTextContent() {
if (textContent.value !== newTextContent.value) {
try {
- await rpc.writeStaticAssets([{
+ await (await useDevtoolsRpc()).call('writeStaticAssets', [{
path: asset.value.path,
content: newTextContent.value,
override: true,
@@ -133,7 +133,7 @@ const supportsPreview = computed(() => {
const deleteDialog = ref(false)
async function deleteAsset() {
try {
- await rpc.deleteStaticAsset(asset.value.filePath)
+ await (await useDevtoolsRpc()).call('deleteStaticAsset', asset.value.filePath)
asset.value = undefined as any
deleteDialog.value = false
devtoolsUiShowNotification({
@@ -169,7 +169,7 @@ async function renameAsset() {
try {
const extension = parts.slice(-1)[0]?.split('.').slice(-1)[0]
const fullPath = `${parts.slice(0, -1).join('/')}/${newName.value}.${extension}`
- await rpc.renameStaticAsset(asset.value.filePath, fullPath)
+ await (await useDevtoolsRpc()).call('renameStaticAsset', asset.value.filePath, fullPath)
asset.value = undefined as any
renameDialog.value = false
devtoolsUiShowNotification({
diff --git a/packages/devtools/client/components/AssetDropZone.vue b/packages/devtools/client/components/AssetDropZone.vue
index ef9fa7bd9e..e4862af3dd 100644
--- a/packages/devtools/client/components/AssetDropZone.vue
+++ b/packages/devtools/client/components/AssetDropZone.vue
@@ -3,7 +3,7 @@ import type { AssetEntry } from '~/../src/types'
import { useEventListener, useVModel } from '@vueuse/core'
import { ref } from 'vue'
import { devtoolsUiShowNotification } from '#imports'
-import { rpc, wsConnecting, wsError } from '~/composables/rpc'
+import { useDevtoolsRpc, wsConnecting, wsError } from '~/composables/rpc'
import { telemetry } from '~/composables/telemetry'
const props = defineProps({
@@ -94,7 +94,7 @@ async function uploadFiles() {
content,
})
}
- await rpc.writeStaticAssets([...uploadFiles], props.folder).then(() => {
+ await (await useDevtoolsRpc()).call('writeStaticAssets', [...uploadFiles], props.folder).then(() => {
close()
devtoolsUiShowNotification({
message: 'Files uploaded successfully!',
diff --git a/packages/devtools/client/components/BuildAnalyzeDetails.vue b/packages/devtools/client/components/BuildAnalyzeDetails.vue
index 7a1704bfcd..1b2ffc75d0 100644
--- a/packages/devtools/client/components/BuildAnalyzeDetails.vue
+++ b/packages/devtools/client/components/BuildAnalyzeDetails.vue
@@ -3,7 +3,7 @@ import type { AnalyzeBuildMeta } from '../../src/types'
import { formatTimeAgo } from '@vueuse/core'
import { computed, ref } from 'vue'
import { useRuntimeConfig } from '#imports'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
const props = defineProps<{
current: AnalyzeBuildMeta
@@ -45,7 +45,7 @@ function formatFileSize(bytes: number) {
}
async function clear(name: string) {
- return rpc.clearAnalyzeBuilds([name])
+ return (await useDevtoolsRpc()).call('clearAnalyzeBuilds', [name])
}
diff --git a/packages/devtools/client/components/ModuleItem.vue b/packages/devtools/client/components/ModuleItem.vue
index 6e9aa3b1b3..16bebe485b 100644
--- a/packages/devtools/client/components/ModuleItem.vue
+++ b/packages/devtools/client/components/ModuleItem.vue
@@ -1,7 +1,7 @@
@@ -30,7 +34,7 @@ const data = computed(() => ({
v-if="state === 'running'" flex="~ gap-2"
animate-pulse items-center
:title="id ? 'Open the output in the Terminals dock' : undefined"
- @click="id ? rpc.revealTerminal(id) : undefined"
+ @click="id ? revealTerminal(id) : undefined"
>
Upgrading...
diff --git a/packages/devtools/client/components/ModuleItemInstall.vue b/packages/devtools/client/components/ModuleItemInstall.vue
index e57f3aa066..04756109e4 100644
--- a/packages/devtools/client/components/ModuleItemInstall.vue
+++ b/packages/devtools/client/components/ModuleItemInstall.vue
@@ -2,7 +2,7 @@
import type { ModuleActionType, ModuleStaticInfo } from '../../src/types'
import { computed } from 'vue'
import { ModuleDialog } from '~/composables/dialog'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
import { useInstalledModules } from '~/composables/state-modules'
import { processInstallingModules } from '~/composables/state-subprocess'
import { telemetry } from '~/composables/telemetry'
@@ -18,9 +18,14 @@ const installedInfo = computed(() => installedModules.value.find(i => i.name ===
const isInstalled = computed(() => installedInfo.value && installedInfo.value.isPackageModule)
const isUninstallable = computed(() => installedInfo.value && installedInfo.value.isPackageModule && installedInfo.value.isUninstallable)
+async function callModuleAction(type: ModuleActionType, name: string, dry: boolean, sessionId?: string) {
+ const rpc = await useDevtoolsRpc()
+ const method = type === 'install' ? 'installNuxtModule' : 'uninstallNuxtModule'
+ return rpc.call(method, name, dry, sessionId)
+}
+
async function useModuleAction(item: ModuleStaticInfo, type: ModuleActionType) {
- const method = type === 'install' ? rpc.installNuxtModule : rpc.uninstallNuxtModule
- const result = await method(item.npm, true)
+ const result = await callModuleAction(type, item.npm, true)
telemetry(`modules:${type}`, {
moduleName: item.npm,
@@ -45,7 +50,7 @@ async function useModuleAction(item: ModuleStaticInfo, type: ModuleActionType) {
// server registers the very session we're tracking. The execution RPC
// awaits the process, so clearing the pending entry here (no `onTerminalExit`
// needed) settles the UI whether it succeeds or throws.
- await method(item.npm, false, result.processId)
+ await callModuleAction(type, item.npm, false, result.processId)
}
finally {
const index = processInstallingModules.value.findIndex(i => i.processId === result.processId)
diff --git a/packages/devtools/client/components/NpmVersionCheck.vue b/packages/devtools/client/components/NpmVersionCheck.vue
index 15d9f939c6..d121f3f0e6 100644
--- a/packages/devtools/client/components/NpmVersionCheck.vue
+++ b/packages/devtools/client/components/NpmVersionCheck.vue
@@ -4,7 +4,7 @@ import { createTemplatePromise } from '@vueuse/core'
import { ref } from 'vue'
import { useRestartDialogs } from '~/composables/dialog'
import { usePackageUpdate } from '~/composables/npm'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
import { telemetry } from '~/composables/telemetry'
const props = withDefaults(
@@ -49,7 +49,7 @@ async function updateWithConfirm() {
})
}
if (processId && shouldRevealTerminal.value)
- rpc.revealTerminal(processId)
+ (await useDevtoolsRpc()).call('revealTerminal', processId)
}
diff --git a/packages/devtools/client/components/RestartDialogs.vue b/packages/devtools/client/components/RestartDialogs.vue
index e4fb071ea1..4c65fc4c36 100644
--- a/packages/devtools/client/components/RestartDialogs.vue
+++ b/packages/devtools/client/components/RestartDialogs.vue
@@ -3,7 +3,7 @@ import { createTemplatePromise } from '@vueuse/core'
import { useNuxtApp } from '#app/nuxt'
import { useClient } from '~/composables/client'
import { useRestartDialogs } from '~/composables/dialog'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
const nuxt = useNuxtApp()
const state = useRestartDialogs()
@@ -21,7 +21,7 @@ nuxt.hook('devtools:terminal:exit', ({ id, code }) => {
.start(dialog.message)
.then(async (result) => {
if (result) {
- rpc.restartNuxt()
+ (await useDevtoolsRpc()).call('restartNuxt')
setTimeout(() => {
client.value?.app.reload()
}, 500)
diff --git a/packages/devtools/client/components/StorageDetails.vue b/packages/devtools/client/components/StorageDetails.vue
index 29a5d12753..c16f60d196 100644
--- a/packages/devtools/client/components/StorageDetails.vue
+++ b/packages/devtools/client/components/StorageDetails.vue
@@ -6,7 +6,7 @@ import { useAsyncData } from '#app/composables/asyncData'
import { useRouter } from '#app/composables/router'
import { useNuxtApp } from '#app/nuxt'
import { getColorMode } from '~/composables/client'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
import { useSessionState } from '~/composables/utils'
const colorMode = getColorMode()
@@ -18,10 +18,10 @@ const currentStorage = useSessionState('storage:current', '')
const currentItem = ref()
const fileKey = useSessionState('storage:file:state', '')
-const { data: storageMounts } = await useAsyncData('storageMounts', () => rpc.getStorageMounts())
+const { data: storageMounts } = await useAsyncData('storageMounts', async () => (await useDevtoolsRpc()).call('getStorageMounts'))
const { data: storageKeys, refresh: refreshStorageKeys } = await useAsyncData('storageKeys', async () => {
if (currentStorage.value)
- return await rpc.getStorageKeys(currentStorage.value)
+ return (await useDevtoolsRpc()).call('getStorageKeys', currentStorage.value)
return []
})
@@ -70,7 +70,7 @@ const filteredKeys = computed(() => {
})
async function fetchItem(key: string) {
- const content = await rpc.getStorageItem(key)
+ const content = await (await useDevtoolsRpc()).call('getStorageItem', key)
currentItem.value = {
key,
updatedKey: keyName(key),
@@ -86,7 +86,7 @@ async function saveNewItem() {
// If does not exists
const key = `${currentStorage.value}:${newKey.value}`
if (!storageKeys.value?.includes(key))
- await rpc.setStorageItem(key, '')
+ await (await useDevtoolsRpc()).call('setStorageItem', key, '')
router.replace({ query: { storage: currentStorage.value, key } })
newKey.value = ''
@@ -95,14 +95,14 @@ async function saveNewItem() {
async function saveCurrentItem() {
if (!currentItem.value)
return
- await rpc.setStorageItem(currentItem.value.key, currentItem.value.updatedContent)
+ await (await useDevtoolsRpc()).call('setStorageItem', currentItem.value.key, currentItem.value.updatedContent)
await fetchItem(currentItem.value.key)
}
async function removeCurrentItem() {
if (!currentItem.value || !currentStorage.value)
return
- await rpc.removeStorageItem(currentItem.value.key)
+ await (await useDevtoolsRpc()).call('removeStorageItem', currentItem.value.key)
currentItem.value = null
}
@@ -110,8 +110,9 @@ async function renameCurrentItem() {
if (!currentItem.value || !currentStorage.value)
return
const renamedKey = `${currentStorage.value}:${currentItem.value.updatedKey}`
- await rpc.setStorageItem(renamedKey, currentItem.value.updatedContent)
- await rpc.removeStorageItem(currentItem.value.key)
+ const rpc = await useDevtoolsRpc()
+ await rpc.call('setStorageItem', renamedKey, currentItem.value.updatedContent)
+ await rpc.call('removeStorageItem', currentItem.value.key)
router.replace({ query: { storage: currentStorage.value, key: renamedKey } })
}
diff --git a/packages/devtools/client/composables/editor.ts b/packages/devtools/client/composables/editor.ts
index fe744c4bb3..445f0ec369 100644
--- a/packages/devtools/client/composables/editor.ts
+++ b/packages/devtools/client/composables/editor.ts
@@ -1,7 +1,7 @@
import { useClipboard } from '@vueuse/core'
import { useRouter } from '#app/composables/router'
import { devtoolsUiShowNotification } from '#imports'
-import { rpc } from './rpc'
+import { useDevtoolsRpc } from './rpc'
import { useServerConfig, useVirtualFiles } from './state'
import { useCurrentVirtualFile } from './state-routes'
import { telemetry } from './telemetry'
@@ -33,7 +33,7 @@ export function useOpenInEditor() {
router.push('/modules/virtual-files')
}
else {
- await rpc.openInEditor(filepath)
+ await (await useDevtoolsRpc()).call('openInEditor', filepath)
}
}
}
diff --git a/packages/devtools/client/composables/npm.ts b/packages/devtools/client/composables/npm.ts
index 32b227eef7..04534c8744 100644
--- a/packages/devtools/client/composables/npm.ts
+++ b/packages/devtools/client/composables/npm.ts
@@ -2,7 +2,7 @@ import type { NpmCommandOptions } from '../../src/types'
import { satisfies } from 'verkit'
import { computed, ref } from 'vue'
import { useNuxtApp } from '#app/nuxt'
-import { rpc } from './rpc'
+import { useDevtoolsRpc } from './rpc'
import { useAsyncState } from './utils'
export type PackageUpdateState = 'idle' | 'running' | 'updated'
@@ -17,7 +17,7 @@ export function usePackageUpdate(name: string, options?: NpmCommandOptions): Ret
}
export function useNuxtVersion() {
- return useAsyncState('npm:check:nuxt', () => rpc.checkForUpdateFor('nuxt'))
+ return useAsyncState('npm:check:nuxt', async () => (await useDevtoolsRpc()).call('checkForUpdateFor', 'nuxt'))
}
export function satisfyNuxtVersion(range: string) {
@@ -31,7 +31,7 @@ export function satisfyNuxtVersion(range: string) {
function getPackageUpdate(name: string, options?: NpmCommandOptions) {
const nuxt = useNuxtApp()
- const info = useAsyncState(`npm:check:${name}`, () => rpc.checkForUpdateFor(name))
+ const info = useAsyncState(`npm:check:${name}`, async () => (await useDevtoolsRpc()).call('checkForUpdateFor', name))
const state = ref('idle')
@@ -49,7 +49,8 @@ function getPackageUpdate(name: string, options?: NpmCommandOptions) {
if (state.value !== 'idle')
return
- const command = await rpc.getNpmCommand('update', name, options)
+ const rpc = await useDevtoolsRpc()
+ const command = await rpc.call('getNpmCommand', 'update', name, options)
if (!command)
return
@@ -58,7 +59,7 @@ function getPackageUpdate(name: string, options?: NpmCommandOptions) {
state.value = 'running'
- processId.value = (await rpc.runNpmCommand('update', name, options))?.processId
+ processId.value = (await rpc.call('runNpmCommand', 'update', name, options))?.processId
return processId.value
}
@@ -66,7 +67,7 @@ function getPackageUpdate(name: string, options?: NpmCommandOptions) {
async function restart() {
if (state.value !== 'updated')
return
- await rpc.restartNuxt()
+ await (await useDevtoolsRpc()).call('restartNuxt')
}
return {
diff --git a/packages/devtools/client/composables/rpc.ts b/packages/devtools/client/composables/rpc.ts
index 367caddda9..f8df89a77f 100644
--- a/packages/devtools/client/composables/rpc.ts
+++ b/packages/devtools/client/composables/rpc.ts
@@ -1,5 +1,5 @@
import type { DevToolsRpcClient } from '@vitejs/devtools-kit/client'
-import type { AsyncServerFunctions, ClientFunctions } from '../../src/types'
+import type { AsyncServerFunctions, ClientFunctions, ServerFunctions } from '../../src/types'
import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client'
import { useDebounce } from '@vueuse/core'
import { ref, shallowRef } from 'vue'
@@ -22,6 +22,12 @@ export const connectPromise = connectDevToolsRpc()
/**
* Proxy-based RPC object that provides backward-compatible `rpc.functionName()` interface.
* Server functions are called via Vite DevTools Kit's RPC client.
+ *
+ * Kept solely for the public, non-deprecated `NuxtDevtoolsClient.rpc` surface
+ * consumed by third-party module custom tabs (`devtools.rpc.xxx()`). Internal
+ * app code no longer uses this — it calls `rpcClient.value?.call(...)` /
+ * `connectPromise` directly (devframe-native style), the same way this Proxy
+ * does underneath.
*/
export const rpc = new Proxy({} as AsyncServerFunctions, {
get: (_, method: string) => {
@@ -34,6 +40,43 @@ export const rpc = new Proxy({} as AsyncServerFunctions, {
},
})
+/**
+ * Nuxt DevTools' server RPC surface, scoped to the `nuxt:devtools:` namespace
+ * and typed against our own {@link ServerFunctions}.
+ *
+ * This is the shape devframe's native `client.scope(ns).rpc` returns — every id
+ * is auto-prefixed with the namespace, so methods are called by their bare
+ * name (`call('getServerPages')` → `nuxt:devtools:getServerPages`). devframe
+ * types its scoped surface against the global function registry, which Nuxt
+ * DevTools does not augment, so we re-type it here against `ServerFunctions` to
+ * keep full argument/return inference at every call site.
+ */
+export interface DevtoolsScopedRpc {
+ /** Call a server function by its bare (unprefixed) name. */
+ call: (method: T, ...args: Parameters) => Promise>>
+ /** Fire-and-forget a server function; no response is awaited. */
+ callEvent: (method: T, ...args: Parameters) => void
+ /** Call a server function that resolves `undefined` when it isn't registered. */
+ callOptional: (method: T, ...args: Parameters) => Promise> | undefined>
+}
+
+/**
+ * Resolve the connected devframe RPC client and return its view scoped to the
+ * `nuxt:devtools:` namespace (devframe-native `client.scope(...)`).
+ *
+ * Collapses the `rpcClient.value || await connectPromise` connect dance and the
+ * namespace prefixing into one call, so internal app code does:
+ *
+ * ```ts
+ * const rpc = await useDevtoolsRpc()
+ * const pages = await rpc.call('getServerPages')
+ * ```
+ */
+export async function useDevtoolsRpc(): Promise {
+ const client = rpcClient.value || await connectPromise
+ return client.scope(RPC_NAMESPACE).rpc as unknown as DevtoolsScopedRpc
+}
+
async function connectDevToolsRpc(): Promise {
try {
const client = await getDevToolsRpcClient()
diff --git a/packages/devtools/client/composables/state-components.ts b/packages/devtools/client/composables/state-components.ts
index 37a038ce99..20ba712e1b 100644
--- a/packages/devtools/client/composables/state-components.ts
+++ b/packages/devtools/client/composables/state-components.ts
@@ -1,14 +1,14 @@
import type { Component } from 'nuxt/schema'
import { computed } from 'vue'
import { useClient } from './client'
-import { rpc } from './rpc'
+import { useDevtoolsRpc } from './rpc'
import { useAsyncState } from './utils'
const LAZY_COMPONENT_RE = /^Lazy[A-Z]/
export function useComponents() {
const client = useClient()
- const serverComponents = useAsyncState('getComponents', () => rpc.getComponents())
+ const serverComponents = useAsyncState('getComponents', async () => (await useDevtoolsRpc()).call('getComponents'))
const globalComponents = computed(() =>
Object
@@ -29,5 +29,5 @@ export function useComponents() {
}
export function useComponentsRelationships() {
- return useAsyncState('getComponentsRelationships', () => rpc.getComponentsRelationships())
+ return useAsyncState('getComponentsRelationships', async () => (await useDevtoolsRpc()).call('getComponentsRelationships'))
}
diff --git a/packages/devtools/client/composables/state.ts b/packages/devtools/client/composables/state.ts
index c1e282ea72..3665d2c71e 100644
--- a/packages/devtools/client/composables/state.ts
+++ b/packages/devtools/client/composables/state.ts
@@ -4,63 +4,63 @@ import { objectPick } from '@antfu/utils'
import { computed } from 'vue'
import { useFetch } from '#app/composables/fetch'
import { useClientRouter } from './client'
-import { rpc } from './rpc'
+import { useDevtoolsRpc } from './rpc'
import { useAsyncState } from './utils'
export function useServerPages() {
- return useAsyncState('getServerPages', () => rpc.getServerPages())
+ return useAsyncState('getServerPages', async () => (await useDevtoolsRpc()).call('getServerPages'))
}
export function useServerRoutes() {
- return useAsyncState('getServerRoutes', () => rpc.getServerRoutes())
+ return useAsyncState('getServerRoutes', async () => (await useDevtoolsRpc()).call('getServerRoutes'))
}
export function useServerTasks() {
- return useAsyncState('getServerTasks', () => rpc.getServerTasks())
+ return useAsyncState('getServerTasks', async () => (await useDevtoolsRpc()).call('getServerTasks'))
}
export function useServerHooks() {
- return useAsyncState('getServerHooks', () => rpc.getServerHooks()) as Ref
+ return useAsyncState('getServerHooks', async () => (await useDevtoolsRpc()).call('getServerHooks')) as Ref
}
export function useLayouts() {
- return useAsyncState('getServerLayouts', () => rpc.getServerLayouts())
+ return useAsyncState('getServerLayouts', async () => (await useDevtoolsRpc()).call('getServerLayouts'))
}
export function useAutoImports() {
- return useAsyncState('getAutoImports', () => rpc.getAutoImports())
+ return useAsyncState('getAutoImports', async () => (await useDevtoolsRpc()).call('getAutoImports'))
}
export function useStaticAssets() {
- return useAsyncState('getStaticAssets', () => rpc.getStaticAssets())
+ return useAsyncState('getStaticAssets', async () => (await useDevtoolsRpc()).call('getStaticAssets'))
}
export function useServerConfig() {
- return useAsyncState('getServerConfig', () => rpc.getServerConfig())
+ return useAsyncState('getServerConfig', async () => (await useDevtoolsRpc()).call('getServerConfig'))
}
export function useServerDebugContext() {
- return useAsyncState('getServerDebugContext', () => rpc.getServerDebugContext())
+ return useAsyncState('getServerDebugContext', async () => (await useDevtoolsRpc()).call('getServerDebugContext'))
}
export function useServerRuntimeConfig() {
- return useAsyncState('getServerRuntimeConfig', () => rpc.getServerRuntimeConfig())
+ return useAsyncState('getServerRuntimeConfig', async () => (await useDevtoolsRpc()).call('getServerRuntimeConfig'))
}
export function useModuleOptions() {
- return useAsyncState('getModuleOptions', () => rpc.getModuleOptions())
+ return useAsyncState('getModuleOptions', async () => (await useDevtoolsRpc()).call('getModuleOptions'))
}
export function useServerApp() {
- return useAsyncState('getServerApp', () => rpc.getServerApp())
+ return useAsyncState('getServerApp', async () => (await useDevtoolsRpc()).call('getServerApp'))
}
export function useCustomTabs() {
- return useAsyncState('getCustomTabs', () => rpc.getCustomTabs())
+ return useAsyncState('getCustomTabs', async () => (await useDevtoolsRpc()).call('getCustomTabs'))
}
export function useAnalyzeBuildInfo() {
- return useAsyncState('getAnalyzeBuildInfo', () => rpc.getAnalyzeBuildInfo())
+ return useAsyncState('getAnalyzeBuildInfo', async () => (await useDevtoolsRpc()).call('getAnalyzeBuildInfo'))
}
export interface VfsData {
diff --git a/packages/devtools/client/composables/storage-options.ts b/packages/devtools/client/composables/storage-options.ts
index 226805601d..d50aacaac5 100644
--- a/packages/devtools/client/composables/storage-options.ts
+++ b/packages/devtools/client/composables/storage-options.ts
@@ -3,7 +3,7 @@ import type { NuxtDevToolsOptions } from '../../types'
import { watchDebounced } from '@vueuse/core'
import { reactive, toRefs } from 'vue'
import { createDefaultTabOptions } from '../../src/constant'
-import { rpc } from './rpc'
+import { useDevtoolsRpc } from './rpc'
const cache = new Map()
@@ -15,18 +15,26 @@ function getTabOptions(tab: T): ToRefs {
Object.assign(source, options)
watchDebounced(
source,
- async (options) => {
+ (options) => {
// Best-effort persistence: a transient RPC failure here (e.g. the
// connection was torn down and re-established after a dev-server
// reload) shouldn't surface as an uncaught error — the next change
// will simply retry the write.
- rpc.updateOptions(tab, options).catch((error) => {
+ persistOptions(options).catch((error) => {
console.error(`[nuxt-devtools] Failed to persist "${String(tab)}" options`, error)
})
},
diff --git a/packages/devtools/client/composables/telemetry.ts b/packages/devtools/client/composables/telemetry.ts
index 4c1bec0c45..3bce860d04 100644
--- a/packages/devtools/client/composables/telemetry.ts
+++ b/packages/devtools/client/composables/telemetry.ts
@@ -1,5 +1,5 @@
import { userAgentInfo } from './dev-auth'
-import { rpc } from './rpc'
+import { useDevtoolsRpc } from './rpc'
import { useDevToolsOptions } from './storage-options'
export const telemetryEnabled = useDevToolsOptions('behavior').telemetry
@@ -8,15 +8,19 @@ export function telemetry(event: string, payload?: object, immediate = false) {
if (telemetryEnabled.value === false)
return
- rpc.telemetryEvent({
- event,
- browser: userAgentInfo.browser.name,
- browserVersion: userAgentInfo.browser.version,
- os: userAgentInfo.os.name,
- osVersion: userAgentInfo.os.version,
- deviceType: userAgentInfo.device.type,
- ...payload,
- }, immediate).catch((error) => {
+ const send = async () => {
+ return (await useDevtoolsRpc()).call('telemetryEvent', {
+ event,
+ browser: userAgentInfo.browser.name,
+ browserVersion: userAgentInfo.browser.version,
+ os: userAgentInfo.os.name,
+ osVersion: userAgentInfo.os.version,
+ deviceType: userAgentInfo.device.type,
+ ...payload,
+ }, immediate)
+ }
+
+ send().catch((error) => {
// Telemetry is best-effort: a transient RPC failure (e.g. the connection
// was torn down and re-established after a dev-server reload) should
// never surface to the user as an uncaught error.
diff --git a/packages/devtools/client/pages/modules/analyze-build.vue b/packages/devtools/client/pages/modules/analyze-build.vue
index b5ca9b64a7..d35dcfa6da 100644
--- a/packages/devtools/client/pages/modules/analyze-build.vue
+++ b/packages/devtools/client/pages/modules/analyze-build.vue
@@ -4,7 +4,7 @@ import { createTemplatePromise, formatTimeAgo } from '@vueuse/core'
import { computed, ref } from 'vue'
import { definePageMeta } from '#imports'
import { satisfyNuxtVersion } from '~/composables/npm'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
import { useAnalyzeBuildInfo } from '~/composables/state'
import { registerCommands } from '~/composables/state-commands'
import { telemetry } from '~/composables/telemetry'
@@ -32,7 +32,8 @@ const shouldRevealTerminal = ref(false)
const buildNameInput = ref('')
const buildNameConflicted = computed(() => info.value?.builds.some(b => b.name === buildNameInput.value.trim()))
async function start() {
- buildNameInput.value = await rpc.generateAnalyzeBuildName()
+ const rpc = await useDevtoolsRpc()
+ buildNameInput.value = await rpc.call('generateAnalyzeBuildName')
if (!await PromiseConfirm.start())
return
@@ -42,18 +43,18 @@ async function start() {
// `startAnalyzeBuild` refreshes `getAnalyzeBuildInfo` as soon as the session
// registers, so `info.isBuilding` / `info.activeSessionId` drive the UI. It
// also returns the id so we can reveal the dock immediately.
- const sessionId = await rpc.startAnalyzeBuild(buildNameInput.value)
+ const sessionId = await rpc.call('startAnalyzeBuild', buildNameInput.value)
if (shouldRevealTerminal.value)
- rpc.revealTerminal(sessionId)
+ rpc.call('revealTerminal', sessionId)
}
function getDuration(build: AnalyzeBuildMeta) {
return `${((build.endTime - build.startTime) / 1000).toFixed(1)}s`
}
-function revealTerminal() {
+async function revealTerminal() {
if (info.value?.activeSessionId)
- rpc.revealTerminal(info.value.activeSessionId)
+ await (await useDevtoolsRpc()).call('revealTerminal', info.value.activeSessionId)
}
registerCommands(() => [
diff --git a/packages/devtools/client/pages/modules/custom-[name].vue b/packages/devtools/client/pages/modules/custom-[name].vue
index b6254b4008..23056d6b7e 100644
--- a/packages/devtools/client/pages/modules/custom-[name].vue
+++ b/packages/devtools/client/pages/modules/custom-[name].vue
@@ -4,7 +4,7 @@ import { computed, onMounted } from 'vue'
import { useRoute, useRouter } from '#app/composables/router'
import { definePageMeta } from '#imports'
import { isDevAuthed, requestForAuth } from '~/composables/dev-auth'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
import { useAllTabs } from '~/composables/state-tabs'
const props = defineProps<{
@@ -33,6 +33,10 @@ onMounted(() => {
requestForAuth()
}
})
+
+async function customTabAction(name: string, action: number) {
+ await (await useDevtoolsRpc()).call('customTabAction', name, action)
+}
@@ -68,7 +72,7 @@ onMounted(() => {
:title="tab.view.title || tab.title"
:description="tab.view.description"
:actions="tab.view.actions"
- @action="idx => rpc.customTabAction(tab!.name, idx)"
+ @action="idx => customTabAction(tab!.name, idx)"
/>
diff --git a/packages/devtools/client/pages/modules/modules.vue b/packages/devtools/client/pages/modules/modules.vue
index 8fbf7ca45c..15ccf9d8e8 100644
--- a/packages/devtools/client/pages/modules/modules.vue
+++ b/packages/devtools/client/pages/modules/modules.vue
@@ -1,7 +1,7 @@
@@ -49,7 +53,7 @@ registerCommands(() => [
v-for="m of processInstallingModules"
:key="m.processId" block min-h-30
title="Open the output in the Terminals dock"
- @click="rpc.revealTerminal(m.processId)"
+ @click="revealTerminal(m.processId)"
>
`./${compatibilityVersion === 4 ? 'app/' : ''}pages/index.vue`)
+
+async function enablePages() {
+ await (await useDevtoolsRpc()).call('enablePages')
+}
@@ -181,7 +186,7 @@ const pagesPath = computed(() => `./${compatibilityVersion === 4 ? 'app/' : ''}p
{
label: 'Enable Routing',
async handle() {
- return rpc.enablePages()
+ return enablePages()
},
},
]"
diff --git a/packages/devtools/client/pages/modules/timeline.vue b/packages/devtools/client/pages/modules/timeline.vue
index b9e2be49b1..bb30f87a27 100644
--- a/packages/devtools/client/pages/modules/timeline.vue
+++ b/packages/devtools/client/pages/modules/timeline.vue
@@ -2,7 +2,7 @@
import { createTemplatePromise } from '@vueuse/core'
import { definePageMeta, devtoolsUiShowNotification } from '#imports'
import { useOpenInEditor } from '~/composables/editor'
-import { rpc } from '~/composables/rpc'
+import { useDevtoolsRpc } from '~/composables/rpc'
import { useModuleOptions, useServerConfig } from '~/composables/state'
definePageMeta({
@@ -20,10 +20,11 @@ const openInEditor = useOpenInEditor()
async function showPopup() {
try {
- const [source, modified] = await rpc.enableTimeline(true)
+ const rpc = await useDevtoolsRpc()
+ const [source, modified] = await rpc.call('enableTimeline', true)
if (!await Dialog.start(source, modified))
return
- await rpc.enableTimeline(false)
+ await rpc.call('enableTimeline', false)
}
catch {
devtoolsUiShowNotification({
diff --git a/packages/devtools/client/pages/settings.vue b/packages/devtools/client/pages/settings.vue
index 3bf76a67e6..f8b85cd81e 100644
--- a/packages/devtools/client/pages/settings.vue
+++ b/packages/devtools/client/pages/settings.vue
@@ -1,7 +1,7 @@