@@ -60,6 +60,10 @@ export interface PlaygroundProps {
6060
6161const headerHeight = 56 ;
6262
63+ function generateRandomRoomName ( ) {
64+ return `room-${ Math . random ( ) . toString ( 36 ) . substring ( 2 , 10 ) } ` ;
65+ }
66+
6367export default function Playground ( {
6468 logo,
6569 themeColors,
@@ -73,31 +77,30 @@ export default function Playground({
7377 const [ rpcPayload , setRpcPayload ] = useState ( "" ) ;
7478 const [ hasConnected , setHasConnected ] = useState ( false ) ;
7579
80+ // User-entered room name. When empty, a random name is generated
81+ // in tokenFetchOptions for each session.
82+ const [ userRoomName , setUserRoomName ] = useState ( "" ) ;
83+
7684 const [ tokenFetchOptions , setTokenFetchOptions ] =
77- useState < TokenSourceFetchOptions > ( ) ;
85+ useState < TokenSourceFetchOptions > ( ( ) => {
86+ // Always initialize with a roomName so the SDK's token cache
87+ // has a non-empty key set for future equality comparisons.
88+ const opts : TokenSourceFetchOptions = {
89+ roomName : generateRandomRoomName ( ) ,
90+ } ;
91+ if ( initialAgentOptions ) {
92+ opts . agentName = initialAgentOptions . agentName ?? "" ;
93+ opts . agentMetadata = initialAgentOptions . metadata ?? "" ;
94+ }
95+ return opts ;
96+ } ) ;
7897
7998 // Store attributes as an array with stable IDs to prevent disappearing while editing
8099 // Initialize with one empty attribute so the inspector isn't empty on first open
81100 const [ attributeItems , setAttributeItems ] = useState < AttributeItem [ ] > ( [
82101 { id : `attr_initial_${ Date . now ( ) } ` , key : "" , value : "" } ,
83102 ] ) ;
84103
85- // initialize token fetch options from initial values, which can come from config
86- useEffect ( ( ) => {
87- if ( tokenFetchOptions !== undefined || initialAgentOptions === undefined ) {
88- return ;
89- }
90- setTokenFetchOptions ( {
91- agentName : initialAgentOptions ?. agentName ?? "" ,
92- agentMetadata : initialAgentOptions ?. metadata ?? "" ,
93- } ) ;
94- } , [
95- tokenFetchOptions ,
96- initialAgentOptions ,
97- initialAgentOptions ?. agentName ,
98- initialAgentOptions ?. metadata ,
99- ] ) ;
100-
101104 const session = useSession ( tokenSource , tokenFetchOptions ) ;
102105 const { connectionState } = session ;
103106 const agent = useAgent ( session ) ;
@@ -332,14 +335,23 @@ export default function Playground({
332335
333336 < ConfigurationPanelItem title = "Room" >
334337 < div className = "flex flex-col gap-2" >
335- < NameValueRow
338+ < EditableNameValueRow
336339 name = "Room name"
337340 value = {
338341 connectionState === ConnectionState . Connected
339342 ? session . room . name
340- : ""
343+ : userRoomName
341344 }
342345 valueColor = { `${ config . settings . theme_color } -500` }
346+ onValueChange = { ( value ) => {
347+ setUserRoomName ( value ) ;
348+ setTokenFetchOptions ( ( prev ) => ( {
349+ ...prev ,
350+ roomName : value || generateRandomRoomName ( ) ,
351+ } ) ) ;
352+ } }
353+ placeholder = "Auto"
354+ editable = { connectionState !== ConnectionState . Connected }
343355 />
344356 < NameValueRow
345357 name = "Status"
@@ -577,6 +589,7 @@ export default function Playground({
577589 attributeItems ,
578590 tokenFetchOptions ,
579591 setTokenFetchOptions ,
592+ userRoomName ,
580593 ] ) ;
581594
582595 let mobileTabs : PlaygroundTab [ ] = [ ] ;
@@ -644,6 +657,14 @@ export default function Playground({
644657 startSession ( ) ;
645658 } else if ( connectionState === ConnectionState . Connected ) {
646659 session . end ( ) ;
660+ // Generate a new random room name for next connect so the
661+ // SDK fetches a fresh token. User-set names are preserved.
662+ if ( ! userRoomName ) {
663+ setTokenFetchOptions ( ( prev ) => ( {
664+ ...prev ,
665+ roomName : generateRandomRoomName ( ) ,
666+ } ) ) ;
667+ }
647668 }
648669 } }
649670 />
0 commit comments