feat(client): self-contained local service discovery and lifecycle
This commit is contained in:
parent
b6c3a8ea7b
commit
1de3c6e4a6
27 changed files with 535 additions and 480 deletions
|
|
@ -15,7 +15,7 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||
init: (props: {
|
||||
client: OpencodeClient
|
||||
api: OpenCodeClient
|
||||
reload?: () => Promise<{ client: OpencodeClient; api: OpenCodeClient }>
|
||||
discover?: () => Promise<{ client: OpencodeClient; api: OpenCodeClient }>
|
||||
}) => {
|
||||
const abort = new AbortController()
|
||||
let client = props.client
|
||||
|
|
@ -32,12 +32,10 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||
connectedOnce: false,
|
||||
})
|
||||
let stream: AbortController | undefined
|
||||
let pending: Promise<void> | undefined
|
||||
|
||||
function start() {
|
||||
stream?.abort()
|
||||
const controller = new AbortController()
|
||||
const current = client
|
||||
let connected!: () => void
|
||||
const ready = new Promise<void>((resolve) => {
|
||||
connected = resolve
|
||||
|
|
@ -54,7 +52,7 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||
)
|
||||
controller.signal.addEventListener("abort", cancel, { once: true })
|
||||
const error = await (async () => {
|
||||
const response = await current.v2.event.subscribe({
|
||||
const response = await client.v2.event.subscribe({
|
||||
signal: connection.signal,
|
||||
sseMaxRetryAttempts: 0,
|
||||
throwOnError: true,
|
||||
|
|
@ -86,6 +84,17 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||
})
|
||||
if (abort.signal.aborted || controller.signal.aborted) return
|
||||
attempt += 1
|
||||
// Re-resolve the transport before retrying: the server may have
|
||||
// moved (service restarted on a new port) or need starting. Static
|
||||
// transports (--server, standalone) resolve to the same address.
|
||||
if (props.discover) {
|
||||
const next = await props.discover().catch(() => undefined)
|
||||
if (abort.signal.aborted || controller.signal.aborted) return
|
||||
if (next) {
|
||||
client = next.client
|
||||
api = next.api
|
||||
}
|
||||
}
|
||||
setConnection({
|
||||
status: "connecting",
|
||||
attempt,
|
||||
|
|
@ -97,23 +106,6 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||
return ready
|
||||
}
|
||||
|
||||
const reload = props.reload
|
||||
? () => {
|
||||
if (pending) return pending
|
||||
pending = Promise.resolve()
|
||||
.then(props.reload)
|
||||
.then(async (next) => {
|
||||
client = next.client
|
||||
api = next.api
|
||||
if (!abort.signal.aborted) await start()
|
||||
})
|
||||
.finally(() => {
|
||||
pending = undefined
|
||||
})
|
||||
return pending
|
||||
}
|
||||
: undefined
|
||||
|
||||
onMount(() => void start())
|
||||
onCleanup(() => {
|
||||
abort.abort()
|
||||
|
|
@ -146,7 +138,6 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||
return connection.connectedOnce
|
||||
},
|
||||
},
|
||||
reload,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue