summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/context/global-sync.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/app/src/context/global-sync.tsx')
-rw-r--r--packages/app/src/context/global-sync.tsx159
1 files changed, 84 insertions, 75 deletions
diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx
index 86496bad5..2c80f31b1 100644
--- a/packages/app/src/context/global-sync.tsx
+++ b/packages/app/src/context/global-sync.tsx
@@ -14,17 +14,25 @@ import { createStore, produce, reconcile } from "solid-js/store"
import { useLanguage } from "@/context/language"
import type { InitError } from "../pages/error"
import { useGlobalSDK } from "./global-sdk"
-import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap"
+import {
+ bootstrapDirectory,
+ bootstrapGlobal,
+ clearProviderRev,
+ loadGlobalConfigQuery,
+ loadPathQuery,
+ loadProjectsQuery,
+ loadProvidersQuery,
+} from "./global-sync/bootstrap"
import { createChildStoreManager } from "./global-sync/child-store"
import { applyDirectoryEvent, applyGlobalEvent, cleanupDroppedSessionCaches } from "./global-sync/event-reducer"
-import { createRefreshQueue } from "./global-sync/queue"
import { clearSessionPrefetchDirectory } from "./global-sync/session-prefetch"
import { estimateRootSessionTotal, loadRootSessionsWithFallback } from "./global-sync/session-load"
import { trimSessions } from "./global-sync/session-trim"
import type { ProjectMeta } from "./global-sync/types"
import { SESSION_RECENT_LIMIT } from "./global-sync/types"
import { formatServerError } from "@/utils/server-errors"
-import { queryOptions, skipToken, useQueryClient } from "@tanstack/solid-query"
+import { queryOptions, skipToken, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/solid-query"
+import { createRefreshQueue } from "./global-sync/queue"
type GlobalStore = {
ready: boolean
@@ -43,6 +51,18 @@ type GlobalStore = {
export const loadSessionsQuery = (directory: string) =>
queryOptions<null>({ queryKey: [directory, "loadSessions"], queryFn: skipToken })
+export const loadMcpQuery = (directory: string, sdk?: OpencodeClient) =>
+ queryOptions({
+ queryKey: [directory, "mcp"],
+ queryFn: sdk ? () => sdk.mcp.status().then((r) => r.data ?? {}) : skipToken,
+ })
+
+export const loadLspQuery = (directory: string, sdk?: OpencodeClient) =>
+ queryOptions({
+ queryKey: [directory, "lsp"],
+ queryFn: sdk ? () => sdk.lsp.status().then((r) => r.data ?? []) : skipToken,
+ })
+
function createGlobalSync() {
const globalSDK = useGlobalSDK()
const language = useLanguage()
@@ -54,15 +74,34 @@ function createGlobalSync() {
const sessionLoads = new Map<string, Promise<void>>()
const sessionMeta = new Map<string, { limit: number }>()
+ const [configQuery, providerQuery, pathQuery] = useQueries(() => ({
+ queries: [loadGlobalConfigQuery(), loadProvidersQuery(null), loadPathQuery(null), loadProjectsQuery()],
+ }))
+
const [globalStore, setGlobalStore] = createStore<GlobalStore>({
- ready: false,
- path: { state: "", config: "", worktree: "", directory: "", home: "" },
+ get ready() {
+ return bootstrap.isPending
+ },
project: [],
session_todo: {},
- provider: { all: [], connected: [], default: {} },
provider_auth: {},
- config: {},
- reload: undefined,
+ get path() {
+ const EMPTY = { state: "", config: "", worktree: "", directory: "", home: "" }
+ if (pathQuery.isLoading) return EMPTY
+ return pathQuery.data ?? EMPTY
+ },
+ get provider() {
+ const EMPTY = { all: [], connected: [], default: {} }
+ if (providerQuery.isLoading) return EMPTY
+ return providerQuery.data ?? EMPTY
+ },
+ get config() {
+ if (configQuery.isLoading) return {}
+ return configQuery.data ?? {}
+ },
+ get reload() {
+ return updateConfigMutation.isPending ? "pending" : undefined
+ },
})
const queryClient = useQueryClient()
@@ -88,6 +127,22 @@ function createGlobalSync() {
return (setGlobalStore as (...args: unknown[]) => unknown)(...input)
}) as typeof setGlobalStore
+ const bootstrap = useQuery(() => ({
+ queryKey: ["bootstrap"],
+ queryFn: async () => {
+ await bootstrapGlobal({
+ globalSDK: globalSDK.client,
+ requestFailedTitle: language.t("common.requestFailed"),
+ translate: language.t,
+ formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
+ setGlobalStore: setBootStore,
+ queryClient,
+ })
+ bootedAt = Date.now()
+ return bootedAt
+ },
+ }))
+
const set = ((...input: unknown[]) => {
if (input[0] === "project" && (Array.isArray(input[1]) || typeof input[1] === "function")) {
setProjects(input[1] as Project[] | ((draft: Project[]) => Project[]))
@@ -114,10 +169,21 @@ function createGlobalSync() {
const queue = createRefreshQueue({
paused,
- bootstrap,
+ bootstrap: () => queryClient.fetchQuery({ queryKey: ["bootstrap"] }),
bootstrapInstance,
})
+ const sdkFor = (directory: string) => {
+ const cached = sdkCache.get(directory)
+ if (cached) return cached
+ const sdk = globalSDK.createClient({
+ directory,
+ throwOnError: true,
+ })
+ sdkCache.set(directory, sdk)
+ return sdk
+ }
+
const children = createChildStoreManager({
owner,
isBooting: (directory) => booting.has(directory),
@@ -133,19 +199,9 @@ function createGlobalSync() {
clearSessionPrefetchDirectory(directory)
},
translate: language.t,
+ getSdk: sdkFor,
})
- const sdkFor = (directory: string) => {
- const cached = sdkCache.get(directory)
- if (cached) return cached
- const sdk = globalSDK.createClient({
- directory,
- throwOnError: true,
- })
- sdkCache.set(directory, sdk)
- return sdk
- }
-
async function loadSessions(directory: string) {
const pending = sessionLoads.get(directory)
if (pending) return pending
@@ -264,26 +320,13 @@ function createGlobalSync() {
const event = e.details
const recent = bootingRoot || Date.now() - bootedAt < 1500
- if (event.type === "session.error") {
- const error = event.properties.error
- if (error?.name !== "MessageAbortedError") {
- console.error("[global-sync] session error", {
- scope: directory === "global" ? "global" : "workspace",
- directory: directory === "global" ? undefined : directory,
- project: directory === "global" ? undefined : getFilename(directory),
- sessionID: event.properties.sessionID,
- error,
- })
- }
- }
-
if (directory === "global") {
applyGlobalEvent({
event,
project: globalStore.project,
refresh: () => {
if (recent) return
- queue.refresh()
+ bootstrap.refetch()
},
setGlobalProject: setProjects,
})
@@ -309,12 +352,7 @@ function createGlobalSync() {
setSessionTodo,
vcsCache: children.vcsCache.get(directory),
loadLsp: () => {
- void sdkFor(directory)
- .lsp.status()
- .then((x) => {
- setStore("lsp", x.data ?? [])
- setStore("lsp_ready", true)
- })
+ void queryClient.fetchQuery(loadLspQuery(directory, sdkFor(directory)))
},
})
})
@@ -329,23 +367,6 @@ function createGlobalSync() {
}
})
- async function bootstrap() {
- bootingRoot = true
- try {
- await bootstrapGlobal({
- globalSDK: globalSDK.client,
- requestFailedTitle: language.t("common.requestFailed"),
- translate: language.t,
- formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
- setGlobalStore: setBootStore,
- queryClient,
- })
- bootedAt = Date.now()
- } finally {
- bootingRoot = false
- }
- }
-
onMount(() => {
if (typeof requestAnimationFrame === "function") {
eventFrame = requestAnimationFrame(() => {
@@ -361,7 +382,6 @@ function createGlobalSync() {
void globalSDK.event.start()
}, 0)
}
- void bootstrap()
})
const projectApi = {
@@ -374,21 +394,10 @@ function createGlobalSync() {
},
}
- const updateConfig = async (config: Config) => {
- setGlobalStore("reload", "pending")
- return globalSDK.client.global.config
- .update({ config })
- .then(bootstrap)
- .then(() => {
- queue.refresh()
- setGlobalStore("reload", undefined)
- queue.refresh()
- })
- .catch((error) => {
- setGlobalStore("reload", undefined)
- throw error
- })
- }
+ const updateConfigMutation = useMutation(() => ({
+ mutationFn: (config: Config) => globalSDK.client.global.config.update({ config }),
+ onSuccess: () => bootstrap.refetch(),
+ }))
return {
data: globalStore,
@@ -401,8 +410,8 @@ function createGlobalSync() {
},
child: children.child,
peek: children.peek,
- bootstrap,
- updateConfig,
+ // bootstrap,
+ updateConfig: updateConfigMutation.mutateAsync,
project: projectApi,
todo: {
set: setSessionTodo,