chore: cleanup
This commit is contained in:
@@ -30,7 +30,6 @@ describe("pickDirectoriesToEvict", () => {
|
|||||||
describe("loadRootSessionsWithFallback", () => {
|
describe("loadRootSessionsWithFallback", () => {
|
||||||
test("uses limited roots query when supported", async () => {
|
test("uses limited roots query when supported", async () => {
|
||||||
const calls: Array<{ directory: string; roots: true; limit?: number }> = []
|
const calls: Array<{ directory: string; roots: true; limit?: number }> = []
|
||||||
let fallback = 0
|
|
||||||
|
|
||||||
const result = await loadRootSessionsWithFallback({
|
const result = await loadRootSessionsWithFallback({
|
||||||
directory: "dir",
|
directory: "dir",
|
||||||
@@ -39,20 +38,15 @@ describe("loadRootSessionsWithFallback", () => {
|
|||||||
calls.push(query)
|
calls.push(query)
|
||||||
return { data: [] }
|
return { data: [] }
|
||||||
},
|
},
|
||||||
onFallback: () => {
|
|
||||||
fallback += 1
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result.data).toEqual([])
|
expect(result.data).toEqual([])
|
||||||
expect(result.limited).toBe(true)
|
expect(result.limited).toBe(true)
|
||||||
expect(calls).toEqual([{ directory: "dir", roots: true, limit: 10 }])
|
expect(calls).toEqual([{ directory: "dir", roots: true, limit: 10 }])
|
||||||
expect(fallback).toBe(0)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("falls back to full roots query on limited-query failure", async () => {
|
test("falls back to full roots query on limited-query failure", async () => {
|
||||||
const calls: Array<{ directory: string; roots: true; limit?: number }> = []
|
const calls: Array<{ directory: string; roots: true; limit?: number }> = []
|
||||||
let fallback = 0
|
|
||||||
|
|
||||||
const result = await loadRootSessionsWithFallback({
|
const result = await loadRootSessionsWithFallback({
|
||||||
directory: "dir",
|
directory: "dir",
|
||||||
@@ -62,9 +56,6 @@ describe("loadRootSessionsWithFallback", () => {
|
|||||||
if (query.limit) throw new Error("unsupported")
|
if (query.limit) throw new Error("unsupported")
|
||||||
return { data: [] }
|
return { data: [] }
|
||||||
},
|
},
|
||||||
onFallback: () => {
|
|
||||||
fallback += 1
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result.data).toEqual([])
|
expect(result.data).toEqual([])
|
||||||
@@ -73,7 +64,6 @@ describe("loadRootSessionsWithFallback", () => {
|
|||||||
{ directory: "dir", roots: true, limit: 25 },
|
{ directory: "dir", roots: true, limit: 25 },
|
||||||
{ directory: "dir", roots: true },
|
{ directory: "dir", roots: true },
|
||||||
])
|
])
|
||||||
expect(fallback).toBe(1)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -57,14 +57,6 @@ function errorMessage(error: unknown) {
|
|||||||
return "Unknown error"
|
return "Unknown error"
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDevStats(value: {
|
|
||||||
activeDirectoryStores: number
|
|
||||||
evictions: number
|
|
||||||
loadSessionsFullFetchFallback: number
|
|
||||||
}) {
|
|
||||||
;(globalThis as { __OPENCODE_GLOBAL_SYNC_STATS?: typeof value }).__OPENCODE_GLOBAL_SYNC_STATS = value
|
|
||||||
}
|
|
||||||
|
|
||||||
function createGlobalSync() {
|
function createGlobalSync() {
|
||||||
const globalSDK = useGlobalSDK()
|
const globalSDK = useGlobalSDK()
|
||||||
const platform = usePlatform()
|
const platform = usePlatform()
|
||||||
@@ -72,11 +64,6 @@ function createGlobalSync() {
|
|||||||
const owner = getOwner()
|
const owner = getOwner()
|
||||||
if (!owner) throw new Error("GlobalSync must be created within owner")
|
if (!owner) throw new Error("GlobalSync must be created within owner")
|
||||||
|
|
||||||
const stats = {
|
|
||||||
evictions: 0,
|
|
||||||
loadSessionsFallback: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
const sdkCache = new Map<string, OpencodeClient>()
|
const sdkCache = new Map<string, OpencodeClient>()
|
||||||
const booting = new Map<string, Promise<void>>()
|
const booting = new Map<string, Promise<void>>()
|
||||||
const sessionLoads = new Map<string, Promise<void>>()
|
const sessionLoads = new Map<string, Promise<void>>()
|
||||||
@@ -112,15 +99,6 @@ function createGlobalSync() {
|
|||||||
setGlobalStore("session_todo", sessionID, reconcile(todos, { key: "id" }))
|
setGlobalStore("session_todo", sessionID, reconcile(todos, { key: "id" }))
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateStats = (activeDirectoryStores: number) => {
|
|
||||||
if (!import.meta.env.DEV) return
|
|
||||||
setDevStats({
|
|
||||||
activeDirectoryStores,
|
|
||||||
evictions: stats.evictions,
|
|
||||||
loadSessionsFullFetchFallback: stats.loadSessionsFallback,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const paused = () => untrack(() => globalStore.reload) !== undefined
|
const paused = () => untrack(() => globalStore.reload) !== undefined
|
||||||
|
|
||||||
const queue = createRefreshQueue({
|
const queue = createRefreshQueue({
|
||||||
@@ -131,11 +109,6 @@ function createGlobalSync() {
|
|||||||
|
|
||||||
const children = createChildStoreManager({
|
const children = createChildStoreManager({
|
||||||
owner,
|
owner,
|
||||||
markStats: updateStats,
|
|
||||||
incrementEvictions: () => {
|
|
||||||
stats.evictions += 1
|
|
||||||
updateStats(Object.keys(children.children).length)
|
|
||||||
},
|
|
||||||
isBooting: (directory) => booting.has(directory),
|
isBooting: (directory) => booting.has(directory),
|
||||||
isLoadingSessions: (directory) => sessionLoads.has(directory),
|
isLoadingSessions: (directory) => sessionLoads.has(directory),
|
||||||
onBootstrap: (directory) => {
|
onBootstrap: (directory) => {
|
||||||
@@ -207,10 +180,6 @@ function createGlobalSync() {
|
|||||||
directory,
|
directory,
|
||||||
limit,
|
limit,
|
||||||
list: (query) => globalSDK.client.session.list(query),
|
list: (query) => globalSDK.client.session.list(query),
|
||||||
onFallback: () => {
|
|
||||||
stats.loadSessionsFallback += 1
|
|
||||||
updateStats(Object.keys(children.children).length)
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.then((x) => {
|
.then((x) => {
|
||||||
const nonArchived = (x.data ?? [])
|
const nonArchived = (x.data ?? [])
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ describe("createChildStoreManager", () => {
|
|||||||
|
|
||||||
const manager = createChildStoreManager({
|
const manager = createChildStoreManager({
|
||||||
owner,
|
owner,
|
||||||
markStats() {},
|
|
||||||
incrementEvictions() {},
|
|
||||||
isBooting: () => false,
|
isBooting: () => false,
|
||||||
isLoadingSessions: () => false,
|
isLoadingSessions: () => false,
|
||||||
onBootstrap() {},
|
onBootstrap() {},
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
|
|||||||
|
|
||||||
export function createChildStoreManager(input: {
|
export function createChildStoreManager(input: {
|
||||||
owner: Owner
|
owner: Owner
|
||||||
markStats: (activeDirectoryStores: number) => void
|
|
||||||
incrementEvictions: () => void
|
|
||||||
isBooting: (directory: string) => boolean
|
isBooting: (directory: string) => boolean
|
||||||
isLoadingSessions: (directory: string) => boolean
|
isLoadingSessions: (directory: string) => boolean
|
||||||
onBootstrap: (directory: string) => void
|
onBootstrap: (directory: string) => void
|
||||||
@@ -102,7 +100,6 @@ export function createChildStoreManager(input: {
|
|||||||
}
|
}
|
||||||
delete children[directory]
|
delete children[directory]
|
||||||
input.onDispose(directory)
|
input.onDispose(directory)
|
||||||
input.markStats(Object.keys(children).length)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +117,6 @@ export function createChildStoreManager(input: {
|
|||||||
if (list.length === 0) return
|
if (list.length === 0) return
|
||||||
for (const directory of list) {
|
for (const directory of list) {
|
||||||
if (!disposeDirectory(directory)) continue
|
if (!disposeDirectory(directory)) continue
|
||||||
input.incrementEvictions()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +196,6 @@ export function createChildStoreManager(input: {
|
|||||||
})
|
})
|
||||||
|
|
||||||
runWithOwner(input.owner, init)
|
runWithOwner(input.owner, init)
|
||||||
input.markStats(Object.keys(children).length)
|
|
||||||
}
|
}
|
||||||
mark(directory)
|
mark(directory)
|
||||||
const childStore = children[directory]
|
const childStore = children[directory]
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ export async function loadRootSessionsWithFallback(input: RootLoadArgs) {
|
|||||||
limited: true,
|
limited: true,
|
||||||
} as const
|
} as const
|
||||||
} catch {
|
} catch {
|
||||||
input.onFallback()
|
|
||||||
const result = await input.list({ directory: input.directory, roots: true })
|
const result = await input.list({ directory: input.directory, roots: true })
|
||||||
return {
|
return {
|
||||||
data: result.data,
|
data: result.data,
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ export type RootLoadArgs = {
|
|||||||
directory: string
|
directory: string
|
||||||
limit: number
|
limit: number
|
||||||
list: (query: { directory: string; roots: true; limit?: number }) => Promise<{ data?: Session[] }>
|
list: (query: { directory: string; roots: true; limit?: number }) => Promise<{ data?: Session[] }>
|
||||||
onFallback: () => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RootLoadResult = {
|
export type RootLoadResult = {
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import { DialogSelectServer } from "@/components/dialog-select-server"
|
|||||||
import { DialogSettings } from "@/components/dialog-settings"
|
import { DialogSettings } from "@/components/dialog-settings"
|
||||||
import { useCommand, type CommandOption } from "@/context/command"
|
import { useCommand, type CommandOption } from "@/context/command"
|
||||||
import { ConstrainDragXAxis } from "@/utils/solid-dnd"
|
import { ConstrainDragXAxis } from "@/utils/solid-dnd"
|
||||||
import { navStart } from "@/utils/perf"
|
|
||||||
import { DialogSelectDirectory } from "@/components/dialog-select-directory"
|
import { DialogSelectDirectory } from "@/components/dialog-select-directory"
|
||||||
import { DialogEditProject } from "@/components/dialog-edit-project"
|
import { DialogEditProject } from "@/components/dialog-edit-project"
|
||||||
import { Titlebar } from "@/components/titlebar"
|
import { Titlebar } from "@/components/titlebar"
|
||||||
@@ -826,14 +825,6 @@ export default function Layout(props: ParentProps) {
|
|||||||
if (next) prefetchSession(next)
|
if (next) prefetchSession(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
navStart({
|
|
||||||
dir: base64Encode(session.directory),
|
|
||||||
from: params.id,
|
|
||||||
to: session.id,
|
|
||||||
trigger: offset > 0 ? "alt+arrowdown" : "alt+arrowup",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
navigateToSession(session)
|
navigateToSession(session)
|
||||||
queueMicrotask(() => scrollToSession(session.id, `${session.directory}:${session.id}`))
|
queueMicrotask(() => scrollToSession(session.id, `${session.directory}:${session.id}`))
|
||||||
}
|
}
|
||||||
@@ -869,15 +860,6 @@ export default function Layout(props: ParentProps) {
|
|||||||
if (next) prefetchSession(next)
|
if (next) prefetchSession(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
navStart({
|
|
||||||
dir: base64Encode(session.directory),
|
|
||||||
from: params.id,
|
|
||||||
to: session.id,
|
|
||||||
trigger: offset > 0 ? "shift+alt+arrowdown" : "shift+alt+arrowup",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
navigateToSession(session)
|
navigateToSession(session)
|
||||||
queueMicrotask(() => scrollToSession(session.id, `${session.directory}:${session.id}`))
|
queueMicrotask(() => scrollToSession(session.id, `${session.directory}:${session.id}`))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import { usePrompt } from "@/context/prompt"
|
|||||||
import { useComments } from "@/context/comments"
|
import { useComments } from "@/context/comments"
|
||||||
import { usePermission } from "@/context/permission"
|
import { usePermission } from "@/context/permission"
|
||||||
import { SessionHeader, NewSessionView } from "@/components/session"
|
import { SessionHeader, NewSessionView } from "@/components/session"
|
||||||
import { navMark, navParams } from "@/utils/perf"
|
|
||||||
import { same } from "@/utils/same"
|
import { same } from "@/utils/same"
|
||||||
import { createOpenReviewFile } from "@/pages/session/helpers"
|
import { createOpenReviewFile } from "@/pages/session/helpers"
|
||||||
import { createScrollSpy } from "@/pages/session/scroll-spy"
|
import { createScrollSpy } from "@/pages/session/scroll-spy"
|
||||||
@@ -109,46 +108,6 @@ export default function Page() {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
createEffect(
|
|
||||||
on(
|
|
||||||
() => [params.dir, params.id] as const,
|
|
||||||
([dir, id], prev) => {
|
|
||||||
if (!id) return
|
|
||||||
navParams({ dir, from: prev?.[1], to: id })
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
const id = params.id
|
|
||||||
if (!id) return
|
|
||||||
if (!prompt.ready()) return
|
|
||||||
navMark({ dir: params.dir, to: id, name: "storage:prompt-ready" })
|
|
||||||
})
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
const id = params.id
|
|
||||||
if (!id) return
|
|
||||||
if (!terminal.ready()) return
|
|
||||||
navMark({ dir: params.dir, to: id, name: "storage:terminal-ready" })
|
|
||||||
})
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
const id = params.id
|
|
||||||
if (!id) return
|
|
||||||
if (!file.ready()) return
|
|
||||||
navMark({ dir: params.dir, to: id, name: "storage:file-view-ready" })
|
|
||||||
})
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
const id = params.id
|
|
||||||
if (!id) return
|
|
||||||
if (sync.data.message[id] === undefined) return
|
|
||||||
navMark({ dir: params.dir, to: id, name: "session:data-ready" })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const isDesktop = createMediaQuery("(min-width: 768px)")
|
const isDesktop = createMediaQuery("(min-width: 768px)")
|
||||||
const desktopReviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened())
|
const desktopReviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened())
|
||||||
const desktopFileTreeOpen = createMemo(() => isDesktop() && layout.fileTree.opened())
|
const desktopFileTreeOpen = createMemo(() => isDesktop() && layout.fileTree.opened())
|
||||||
@@ -1140,11 +1099,6 @@ export default function Page() {
|
|||||||
anchor={anchor}
|
anchor={anchor}
|
||||||
onRegisterMessage={scrollSpy.register}
|
onRegisterMessage={scrollSpy.register}
|
||||||
onUnregisterMessage={scrollSpy.unregister}
|
onUnregisterMessage={scrollSpy.unregister}
|
||||||
onFirstTurnMount={() => {
|
|
||||||
const id = params.id
|
|
||||||
if (!id) return
|
|
||||||
navMark({ dir: params.dir, to: id, name: "session:first-turn-mounted" })
|
|
||||||
}}
|
|
||||||
lastUserMessageID={lastUserMessage()?.id}
|
lastUserMessageID={lastUserMessage()?.id}
|
||||||
/>
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { For, createEffect, createMemo, on, onCleanup, onMount, Show, type JSX } from "solid-js"
|
import { For, createEffect, createMemo, on, onCleanup, Show, type JSX } from "solid-js"
|
||||||
import { createStore, produce } from "solid-js/store"
|
import { createStore, produce } from "solid-js/store"
|
||||||
import { useNavigate, useParams } from "@solidjs/router"
|
import { useNavigate, useParams } from "@solidjs/router"
|
||||||
import { Button } from "@opencode-ai/ui/button"
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
@@ -72,7 +72,6 @@ export function MessageTimeline(props: {
|
|||||||
anchor: (id: string) => string
|
anchor: (id: string) => string
|
||||||
onRegisterMessage: (el: HTMLDivElement, id: string) => void
|
onRegisterMessage: (el: HTMLDivElement, id: string) => void
|
||||||
onUnregisterMessage: (id: string) => void
|
onUnregisterMessage: (id: string) => void
|
||||||
onFirstTurnMount?: () => void
|
|
||||||
lastUserMessageID?: string
|
lastUserMessageID?: string
|
||||||
}) {
|
}) {
|
||||||
let touchGesture: number | undefined
|
let touchGesture: number | undefined
|
||||||
@@ -516,37 +515,31 @@ export function MessageTimeline(props: {
|
|||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<For each={props.renderedUserMessages}>
|
<For each={props.renderedUserMessages}>
|
||||||
{(message) => {
|
{(message) => (
|
||||||
if (import.meta.env.DEV && props.onFirstTurnMount) {
|
<div
|
||||||
onMount(() => props.onFirstTurnMount?.())
|
id={props.anchor(message.id)}
|
||||||
}
|
data-message-id={message.id}
|
||||||
|
ref={(el) => {
|
||||||
return (
|
props.onRegisterMessage(el, message.id)
|
||||||
<div
|
onCleanup(() => props.onUnregisterMessage(message.id))
|
||||||
id={props.anchor(message.id)}
|
}}
|
||||||
data-message-id={message.id}
|
classList={{
|
||||||
ref={(el) => {
|
"min-w-0 w-full max-w-full": true,
|
||||||
props.onRegisterMessage(el, message.id)
|
"md:max-w-200 2xl:max-w-[1000px]": props.centered,
|
||||||
onCleanup(() => props.onUnregisterMessage(message.id))
|
}}
|
||||||
|
>
|
||||||
|
<SessionTurn
|
||||||
|
sessionID={sessionID() ?? ""}
|
||||||
|
messageID={message.id}
|
||||||
|
lastUserMessageID={props.lastUserMessageID}
|
||||||
|
classes={{
|
||||||
|
root: "min-w-0 w-full relative",
|
||||||
|
content: "flex flex-col justify-between !overflow-visible",
|
||||||
|
container: "w-full px-4 md:px-6",
|
||||||
}}
|
}}
|
||||||
classList={{
|
/>
|
||||||
"min-w-0 w-full max-w-full": true,
|
</div>
|
||||||
"md:max-w-200 2xl:max-w-[1000px]": props.centered,
|
)}
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SessionTurn
|
|
||||||
sessionID={sessionID() ?? ""}
|
|
||||||
messageID={message.id}
|
|
||||||
lastUserMessageID={props.lastUserMessageID}
|
|
||||||
classes={{
|
|
||||||
root: "min-w-0 w-full relative",
|
|
||||||
content: "flex flex-col justify-between !overflow-visible",
|
|
||||||
container: "w-full px-4 md:px-6",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
import { uuid } from "@/utils/uuid"
|
|
||||||
|
|
||||||
type Nav = {
|
|
||||||
id: string
|
|
||||||
dir?: string
|
|
||||||
from?: string
|
|
||||||
to: string
|
|
||||||
trigger?: string
|
|
||||||
start: number
|
|
||||||
marks: Record<string, number>
|
|
||||||
logged: boolean
|
|
||||||
timer?: ReturnType<typeof setTimeout>
|
|
||||||
}
|
|
||||||
|
|
||||||
const dev = import.meta.env.DEV
|
|
||||||
|
|
||||||
const key = (dir: string | undefined, to: string) => `${dir ?? ""}:${to}`
|
|
||||||
|
|
||||||
const now = () => performance.now()
|
|
||||||
|
|
||||||
const navs = new Map<string, Nav>()
|
|
||||||
const pending = new Map<string, string>()
|
|
||||||
const active = new Map<string, string>()
|
|
||||||
|
|
||||||
const required = [
|
|
||||||
"session:params",
|
|
||||||
"session:data-ready",
|
|
||||||
"session:first-turn-mounted",
|
|
||||||
"storage:prompt-ready",
|
|
||||||
"storage:terminal-ready",
|
|
||||||
"storage:file-view-ready",
|
|
||||||
]
|
|
||||||
|
|
||||||
function flush(id: string, reason: "complete" | "timeout") {
|
|
||||||
if (!dev) return
|
|
||||||
const nav = navs.get(id)
|
|
||||||
if (!nav) return
|
|
||||||
if (nav.logged) return
|
|
||||||
|
|
||||||
nav.logged = true
|
|
||||||
if (nav.timer) clearTimeout(nav.timer)
|
|
||||||
|
|
||||||
const baseName = nav.marks["navigate:start"] !== undefined ? "navigate:start" : "session:params"
|
|
||||||
const base = nav.marks[baseName] ?? nav.start
|
|
||||||
|
|
||||||
const ms = Object.fromEntries(
|
|
||||||
Object.entries(nav.marks)
|
|
||||||
.slice()
|
|
||||||
.sort(([a], [b]) => a.localeCompare(b))
|
|
||||||
.map(([name, t]) => [name, Math.round((t - base) * 100) / 100]),
|
|
||||||
)
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
"perf.session-nav " +
|
|
||||||
JSON.stringify({
|
|
||||||
type: "perf.session-nav.v0",
|
|
||||||
id: nav.id,
|
|
||||||
dir: nav.dir,
|
|
||||||
from: nav.from,
|
|
||||||
to: nav.to,
|
|
||||||
trigger: nav.trigger,
|
|
||||||
base: baseName,
|
|
||||||
reason,
|
|
||||||
ms,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
navs.delete(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
function maybeFlush(id: string) {
|
|
||||||
if (!dev) return
|
|
||||||
const nav = navs.get(id)
|
|
||||||
if (!nav) return
|
|
||||||
if (nav.logged) return
|
|
||||||
if (!required.every((name) => nav.marks[name] !== undefined)) return
|
|
||||||
flush(id, "complete")
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensure(id: string, data: Omit<Nav, "marks" | "logged" | "timer">) {
|
|
||||||
const existing = navs.get(id)
|
|
||||||
if (existing) return existing
|
|
||||||
|
|
||||||
const nav: Nav = {
|
|
||||||
...data,
|
|
||||||
marks: {},
|
|
||||||
logged: false,
|
|
||||||
}
|
|
||||||
nav.timer = setTimeout(() => flush(id, "timeout"), 5000)
|
|
||||||
navs.set(id, nav)
|
|
||||||
return nav
|
|
||||||
}
|
|
||||||
|
|
||||||
export function navStart(input: { dir?: string; from?: string; to: string; trigger?: string }) {
|
|
||||||
if (!dev) return
|
|
||||||
|
|
||||||
const id = uuid()
|
|
||||||
const start = now()
|
|
||||||
const nav = ensure(id, { ...input, id, start })
|
|
||||||
nav.marks["navigate:start"] = start
|
|
||||||
|
|
||||||
pending.set(key(input.dir, input.to), id)
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
export function navParams(input: { dir?: string; from?: string; to: string }) {
|
|
||||||
if (!dev) return
|
|
||||||
|
|
||||||
const k = key(input.dir, input.to)
|
|
||||||
const pendingId = pending.get(k)
|
|
||||||
if (pendingId) pending.delete(k)
|
|
||||||
const id = pendingId ?? uuid()
|
|
||||||
|
|
||||||
const start = now()
|
|
||||||
const nav = ensure(id, { ...input, id, start, trigger: pendingId ? "key" : "route" })
|
|
||||||
nav.marks["session:params"] = start
|
|
||||||
|
|
||||||
active.set(k, id)
|
|
||||||
maybeFlush(id)
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
export function navMark(input: { dir?: string; to: string; name: string }) {
|
|
||||||
if (!dev) return
|
|
||||||
|
|
||||||
const id = active.get(key(input.dir, input.to))
|
|
||||||
if (!id) return
|
|
||||||
|
|
||||||
const nav = navs.get(id)
|
|
||||||
if (!nav) return
|
|
||||||
if (nav.marks[input.name] !== undefined) return
|
|
||||||
|
|
||||||
nav.marks[input.name] = now()
|
|
||||||
maybeFlush(id)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user