fix(client): publish current session provide bundle as one reactive projection

A provider roster change under a stable current id rematerialized every
scope's bundle but nothing notified React: SessionProvider resolved the
bundle from a current-id subscription only, so mounted entries kept the
obsolete hook/prop schema until an unrelated re-render. The sessions
service now owns an atomic currentProvide observable fed by both current
writes and roster changes; the renderer host exposes it as
sessions.provide, replacing the current/provideInfo/maybeProvideInfo
trio, and both providers subscribe to it.
This commit is contained in:
imccyu
2026-07-28 02:53:50 +08:00
parent c4df0628db
commit a0b618abb9
15 changed files with 222 additions and 95 deletions
@@ -87,6 +87,9 @@ async function bench(snapshot: ConversationSnapshot) {
// Provide-channel contributions land in this bundle the way the runtime
// materializes them; the renderer host serves it through provideInfo.
const provided: { hooks: Record<string, unknown>; props: Record<string, unknown> } = { hooks: {}, props: {} }
// Identity-stable currentProvide snapshot (uSES getSnapshot contract),
// materialized on first render after the provide contributions landed.
let infoCell: { sessionId: SessionId; hooks: Record<string, unknown>; props: Record<string, unknown> } | undefined
const sessionsFake = {
list,
binding: (id: SessionId) => (id === SID
@@ -103,9 +106,10 @@ async function bench(snapshot: ConversationSnapshot) {
provideInfo: (id: string) => (id === SID
? { sessionId: SID, hooks: { session, ...provided.hooks }, props: provided.props }
: undefined),
maybeProvideInfo: (id: string | undefined) => (id === SID
? { sessionId: SID, hooks: { session, ...provided.hooks }, props: provided.props }
: { hooks: provided.hooks, props: provided.props }),
currentProvide: {
getSnapshot: () => infoCell ??= { sessionId: SID, hooks: { session, ...provided.hooks }, props: provided.props },
subscribe: () => () => {},
},
create: vi.fn(),
open: vi.fn(),
}