refactor(client): keep pending interaction change UI-scoped
This commit is contained in:
@@ -219,14 +219,17 @@ export function apply(ctx: Context): void {
|
||||
console.error('[web-runtime] history reconnect failed:', error)
|
||||
}
|
||||
},
|
||||
onDisconnected: () => {
|
||||
// Reconnect replays flow from stream open, ahead of onConnected, so each
|
||||
// generation death is the only safe moment to drop generation-owned state.
|
||||
sessions.handleDisconnected()
|
||||
try {
|
||||
sessionHistory.handleDisconnected()
|
||||
} catch (error) {
|
||||
console.error('[web-runtime] history disconnect failed:', error)
|
||||
onStateChange: (state) => {
|
||||
// Generation death fires before any next-generation frame can arrive
|
||||
// (reconnect replays flow from stream open, ahead of onConnected):
|
||||
// the only safe moment to drop generation-scoped interaction state.
|
||||
if (state === 'reconnecting') {
|
||||
sessions.handleDisconnected()
|
||||
try {
|
||||
sessionHistory.handleDisconnected()
|
||||
} catch (error) {
|
||||
console.error('[web-runtime] history disconnect failed:', error)
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -791,9 +791,8 @@ export class SessionManager {
|
||||
* send no frame, so stale statuses and buffered answerable frames must not
|
||||
* survive into the next generation — mux-open replay re-adds every still-pending
|
||||
* request with its live rpcId.
|
||||
*/
|
||||
*/
|
||||
handleDisconnected(): void {
|
||||
for (const session of this.sessions.values()) session.handleDisconnected()
|
||||
if (this.pendingInteractions.size > 0) {
|
||||
this.pendingInteractions.clear()
|
||||
this.notifier.markDirty()
|
||||
|
||||
@@ -393,9 +393,8 @@ export class Session implements SessionFace {
|
||||
}
|
||||
|
||||
/** Reconnect rebuild (manager calls this on onConnected for instances that were opened):
|
||||
* reset the window and rerun open. Pending waits reset at generation death, before the next
|
||||
* baseline replay can arrive, so this method preserves freshly replayed waits. Invalidates
|
||||
* any in-flight open first — its history request rode the dead connection and must not settle
|
||||
* reset the window and rerun open; pending waits for the baseline replay. Invalidates any
|
||||
* in-flight open first — its history request rode the dead connection and must not settle
|
||||
* the fresh generation into 'error' (audit S4). */
|
||||
async resync(): Promise<void> {
|
||||
// The queue mirror is NOT cleared here: onConnected (which drives resync)
|
||||
@@ -411,6 +410,10 @@ export class Session implements SessionFace {
|
||||
this.events = []
|
||||
this.views = []
|
||||
this.baseSeq = 0
|
||||
// Superseded, not settled: the baseline replay re-sends still-pending requested frames verbatim
|
||||
// (same rpcId), re-minting fresh waits; a stale reference's respond() still reaches the host.
|
||||
this.pending.clear()
|
||||
this.pendingRev++
|
||||
this.subscribedLastSeq = null
|
||||
this.liveBuffer = []
|
||||
this.notifier.markDirty()
|
||||
@@ -439,16 +442,6 @@ export class Session implements SessionFace {
|
||||
|
||||
// ---- Manager-only entry points (@internal; never called by the UI) ----
|
||||
|
||||
/** Discard generation-scoped waits before a next-generation replay can arrive. */
|
||||
handleDisconnected(): void {
|
||||
if (this.pending.size === 0) return
|
||||
// Superseded, not settled: a stale reference may already be responding,
|
||||
// and the replay re-mints each still-pending request with the same rpcId.
|
||||
this.pending.clear()
|
||||
this.pendingRev++
|
||||
this.notifier.markDirty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Mux frame arrival (the dispatch switch).
|
||||
* @param rpcId - the frame envelope id (the respond backfill key for requested frames).
|
||||
|
||||
Reference in New Issue
Block a user