% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/globals.R
\name{register_session}
\alias{register_session}
\alias{unregister_session}
\alias{enable_input_broadcast}
\alias{disable_input_broadcast}
\alias{enable_input_sync}
\alias{disable_input_sync}
\alias{get_handler}
\alias{set_handler}
\title{Shiny session registration and cross-tab synchronization}
\usage{
register_session(session)

unregister_session(session)

enable_input_broadcast(
  session = shiny::getDefaultReactiveDomain(),
  once = FALSE
)

disable_input_broadcast(session = shiny::getDefaultReactiveDomain())

enable_input_sync(session = shiny::getDefaultReactiveDomain(), once = FALSE)

disable_input_sync(session = shiny::getDefaultReactiveDomain())

get_handler(name, session = shiny::getDefaultReactiveDomain())

set_handler(name, handler, session = shiny::getDefaultReactiveDomain())
}
\arguments{
\item{session}{A Shiny session object or session proxy (created by
\code{\link[shiny]{moduleServer}}). Most functions in this family default
to \code{shiny::getDefaultReactiveDomain()} so callers inside module
server functions do not need to pass it explicitly.
\code{register_session} and \code{unregister_session} require an explicit
value.}

\item{once}{Logical; if \code{TRUE}, resume the suspended observer for a
single run via \code{$run()} instead of permanently re-activating it with
\code{$resume()}.  Useful for one-shot snapshots without installing a
persistent observer.}

\item{name}{A single character string identifying a named slot in the
session's handler list (used by \code{get_handler} and
\code{set_handler}).  Three names are reserved for internal use and will
trigger an error if passed to \code{set_handler}:
\code{"event_handler"}, \code{"broadcast_handler"}, and
\code{"input_sync_handler"}.}

\item{handler}{A Shiny Observer object created by \code{shiny::observe()},
or \code{NULL} to clear the named slot (used by \code{set_handler}).
Passing any other object type raises an error.}
}
\value{
\code{register_session} returns the session token (\code{session$token})
invisibly; it is idempotent and safe to call multiple times for the same
session.

\code{unregister_session} returns \code{NULL} invisibly; it is idempotent.

\code{enable_input_broadcast}, \code{disable_input_broadcast},
\code{enable_input_sync}, and \code{disable_input_sync} all return
invisibly.  They are silent no-ops when the session is already closed.

\code{get_handler} returns the named \code{Observer} object stored under
\code{name}, or \code{NULL} if the slot is empty or the session is closed.

\code{set_handler} returns \code{TRUE} invisibly when it successfully
installs the handler, or \code{FALSE} invisibly when the session is already
closed.
}
\description{
Shiny session registration and cross-tab synchronization
}
\details{
\subsection{Session registration}{

\strong{\code{register_session()}} — Call once at the top of every Shiny
module server function.  It is idempotent: calling it a second time on the
same session safely refreshes the session object and URL in the registry
entry without re-creating observers.

Internally it creates an entry in the application-global session registry
(initialized by \code{\link{init_app}}), resolves a \code{shared_id} token
shared across browser tabs from the \code{?shared_id=...} URL query string
(or generates a random 26-character string when absent), sets up the
per-session reactive event bus, and — for named module sessions — sends a
\code{shidashi.register_module_token} custom message to bind the module
namespace to its session token on the JavaScript side.

\strong{\code{unregister_session()}} — Removes the session entry from the
registry and destroys all attached observers.  This is called automatically
when the session ends via the \code{onSessionEnded} hook installed by
\code{register_session()}.  Direct calls are only needed for explicit early
cleanup (e.g. in tests).

}
\subsection{Session-scoped handlers}{

Each registered session maintains a named slot list for Shiny
\code{Observer} objects called \emph{handlers}.  This provides a lightweight
system for attaching module-level life-cycle hooks that are tied to the
session's lifetime.

\strong{User-defined handlers — \code{get_handler()} / \code{set_handler()}}

\code{set_handler(name, handler)} installs \code{handler} under \code{name},
first suspending and destroying any \code{Observer} already stored there.
Pass \code{handler = NULL} to clear the slot.  Returns \code{FALSE}
invisibly if the session is already closed.

\code{get_handler(name)} retrieves the stored \code{Observer} (or
\code{NULL}).  It auto-registers the session if not yet registered and
returns \code{NULL} gracefully if the session is closed.

Three handler names are reserved for internal shidashi infrastructure and
will raise an error if passed to \code{set_handler}:
\code{"event_handler"}, \code{"broadcast_handler"}, and
\code{"input_sync_handler"}.

\strong{Built-in cross-tab sync handlers}

shidashi installs two opt-in \code{Observer} slots in every registered
session (both start \emph{suspended}):

\describe{
  \item{Input broadcast (\code{enable_input_broadcast()} /
        \code{disable_input_broadcast()})}{Continuously monitors the
        session's \code{input} values and, whenever they change, pushes a
        snapshot to the client via \code{shidashi.cache_session_input}.
        Other browser tabs sharing the same \code{shared_id} can read this
        cached snapshot to restore or compare input state.}
  \item{Input sync (\code{enable_input_sync()} /
        \code{disable_input_sync()})}{Listens for serialized input maps
        broadcast by \emph{other} sessions sharing the same
        \code{shared_id} via the root-session \code{@shidashi@} input.
        Values differing from the local \code{input} are written into the
        session's private \code{inputs} \code{reactiveValues}.  Messages
        from the same session are ignored to prevent feedback loops.}
}

Both observers run at priority \code{-100000} (after all ordinary reactive
computations have settled).  Use \code{once = TRUE} to trigger a single
cycle without permanently resuming the observer.  The \code{disable_*}
variants suspend the observer and are silent no-ops when the session has
already ended.

}
\subsection{Session life-cycle}{

\preformatted{
init_app()                       # global.R, once per app start
    |
    v
register_session(session)        # top of each module server()
    |
    v
... reactive code ...
    get_handler() / set_handler() # attach user-defined session observers
    enable_input_broadcast()      # optional: push inputs to browser cache
    enable_input_sync()           # optional: receive peer-tab inputs
    |
    v
session ends -> unregister_session()  # runs automatically
}

}
}
\examples{

library(shiny)

# --- Basic usage in a module server ---
server <- function(input, output, session) {
  shidashi::register_session(session)

  # opt-in to cross-tab input broadcast (suspended by default)
  shidashi::enable_input_broadcast(session)

  # opt-in to receive inputs from peer tabs
  shidashi::enable_input_sync(session)

  # get_theme must be called within a reactive context
  output$plot <- renderPlot({
    theme <- shidashi::get_theme()
    par(bg = theme$background, fg = theme$foreground)
    plot(1:10)
  })
}

# --- Named handler: attach a reusable session-scoped observer ---
server2 <- function(input, output, session) {
  shidashi::register_session(session)

  cleanup <- shiny::observe({
    # ... module-level teardown logic ...
    shidashi::set_handler("my_cleanup", NULL, session)
  }, suspended = TRUE, domain = session)

  shidashi::set_handler("my_cleanup", cleanup, session)

  # retrieve and resume the observer elsewhere in the same session
  h <- shidashi::get_handler("my_cleanup", session)
  if (!is.null(h)) h$resume()
}

}
