fix(desktop): scope Bot Screen display.* to the bot backend profile
display.* handlers are @_profile_scoped: without an explicit profile param the gateway answers for the launch home, so every Bot Mode screen pane attached to :20. Dedicated secondaries forward params unchanged, so displayRequest now sends the route backend profile on every call.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* screen pane. The event must also have arrived on the bot's own connection.
|
||||
*/
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type * as routing from './routing'
|
||||
import type { RosterRow } from './types'
|
||||
@@ -79,10 +79,41 @@ describe('isEventForBotScreen', () => {
|
||||
})
|
||||
|
||||
describe('displayRequest', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
routeMock.mockReturnValue(null)
|
||||
})
|
||||
|
||||
it('rejects instead of throwing synchronously for a row whose connection was removed', async () => {
|
||||
routeMock.mockReturnValue(null)
|
||||
|
||||
await expect(displayRequest(orphan, 'display.status')).rejects.toThrow(/no connection owner/)
|
||||
expect(host.requestProfile).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('scopes display.status to the bot backend profile instead of the launch display', async () => {
|
||||
routeMock.mockReturnValue({ connectionId: 'conn-b', profile: 'home-ops' })
|
||||
vi.mocked(host.requestProfile).mockResolvedValue({})
|
||||
|
||||
await displayRequest({ name: 'home-ops' } as RosterRow, 'display.status')
|
||||
|
||||
expect(host.requestProfile).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ connectionId: 'conn-b', profile: 'home-ops' }),
|
||||
'display.status',
|
||||
{ profile: 'home-ops' }
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps caller params alongside the injected profile', async () => {
|
||||
routeMock.mockReturnValue({ connectionId: 'conn-b', profile: 'home-ops' })
|
||||
vi.mocked(host.requestProfile).mockResolvedValue({})
|
||||
|
||||
await displayRequest({ name: 'home-ops' } as RosterRow, 'display.observe', { viewer_id: 'v1' })
|
||||
|
||||
expect(host.requestProfile).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ connectionId: 'conn-b', profile: 'home-ops' }),
|
||||
'display.observe',
|
||||
{ viewer_id: 'v1', profile: 'home-ops' }
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -121,7 +121,16 @@ export function displayRequest<T>(bot: RosterRow, method: string, params: Record
|
||||
return Promise.reject(new Error(`Bot ${bot.name} has no connection owner`))
|
||||
}
|
||||
|
||||
return host.requestProfile<T>(route, method, params)
|
||||
// display.* handlers are @_profile_scoped: without an explicit `profile` the
|
||||
// gateway answers for the LAUNCH home, so every bot pane streams :20 (#120966).
|
||||
// Dedicated secondaries forward params unchanged (only shared-primary routes
|
||||
// get `profile` injected downstream), so scope here, at the one choke point
|
||||
// every Bot Screen RPC flows through. The route owns the identity: a caller
|
||||
// param never overrides it. (Inline `targetProfile || profile` like the other
|
||||
// call sites, so partial `./routing` mocks keep working.)
|
||||
const profile = typeof route === 'string' ? route : route.targetProfile || route.profile
|
||||
|
||||
return host.requestProfile<T>(route, method, { ...params, profile })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,7 +72,9 @@ it('a portal status reply superseded by a newer status request does not move run
|
||||
)
|
||||
|
||||
const view = renderHook(() => useScreenPortalState(bot))
|
||||
expect(host.requestProfile).toHaveBeenCalledWith('ops', 'display.status', {})
|
||||
// `displayRequest` injects the route's profile at the choke point, so the
|
||||
// RPC carries it even when the caller passed no params (#120966).
|
||||
expect(host.requestProfile).toHaveBeenCalledWith('ops', 'display.status', { profile: 'ops' })
|
||||
|
||||
// The pane opens while the portal's fetch is still in flight and asks again (newer request).
|
||||
const paneRequest = beginScreenStatusRequest(bot)
|
||||
|
||||
Reference in New Issue
Block a user