Skip to content

Support modifying SharedState by shared token and propagating to all linked clients #6335

@masenf

Description

@masenf

Summary

When modifying a SharedState by its shared token (rather than a private client token), the update is not propagated to any of the clients linked to that shared state. This makes it impossible to push shared state updates from external contexts like API route webhooks where no private client token is available — only the shared state token is known.

Current Behavior

The shared state system works correctly when events flow through a private client token:

  1. app.modify_state(private_token) is called
  2. modify_state_with_links patches in the linked shared state
  3. After the event handler modifies the shared state, _modify_linked_states collects dirty vars and calls _do_update_other_tokens() to propagate to all other linked clients
  4. All linked clients receive the delta

However, when code calls app.modify_state(shared_token) directly with a shared state token:

  1. The state is loaded under the shared token's ident
  2. modify_state_with_links checks for _reflex_internal_links — this attribute represents outgoing links, which the shared state itself doesn't have
  3. _modify_linked_states is never called, so no propagation happens
  4. The delta is emitted only to token.ident (the shared token), but no browser clients are listening on that token — they listen on their private tokens
  5. No clients receive the update

Expected Behavior

When app.modify_state(shared_token) is called with a shared state token:

  1. The shared state should be loaded and modifiable as it is today
  2. After modification, the system should look up all client tokens in _linked_from on the shared state
  3. Each linked client should receive the delta, the same way _do_update_other_tokens works today

Use Case

A common pattern is modifying shared state from an API route / webhook handler, where only the shared state token is known (e.g., a record_id or room_id):

@rx.api(path="/webhook/{record_id}")
async def handle_webhook(record_id: str, payload: dict):
    token = _substate_key(record_id, SessionState)
    async with app.modify_state(token) as state:
        session = await state.get_state(SessionState)
        session.update_from_webhook(payload)
    # All clients linked to this shared state should see the update

Today, users attempting this pattern resort to manually calling internal APIs like _do_update_other_tokens, which partially works but breaks subsequent event handler deltas in the original tab (reported on Discord).

Relevant Code

Possible Approach

In app.modify_state (or modify_state_with_links), detect when the token refers to a shared state (e.g., check if the loaded state has _linked_from with entries). If so, after modification:

  1. Collect dirty vars from the modified state
  2. Use _linked_from to get all affected client tokens
  3. Call _do_update_other_tokens (or equivalent) to propagate the delta to each linked client
  4. Skip emitting the delta to the shared token itself (no browser is listening on it)

Metadata

Metadata

Assignees

Labels

enhancementAnything you want improved

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions