Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions content/contributing/livetemplate.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Contributing to LiveTemplate Core Library"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "CONTRIBUTING.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Contributing to LiveTemplate Core Library
Expand Down
4 changes: 2 additions & 2 deletions content/guides/ephemeral-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Ephemeral Components Guide"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/guides/ephemeral-components.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Ephemeral Components Guide
Expand Down
4 changes: 2 additions & 2 deletions content/guides/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "LiveTemplate Observability Guide"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/guides/OBSERVABILITY.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# LiveTemplate Observability Guide
Expand Down
4 changes: 2 additions & 2 deletions content/guides/progressive-complexity.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Progressive Complexity Guide"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/guides/progressive-complexity.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Progressive Complexity Guide
Expand Down
4 changes: 2 additions & 2 deletions content/guides/scaling.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "LiveTemplate Scaling Guide"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/guides/SCALING.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# LiveTemplate Scaling Guide
Expand Down
4 changes: 2 additions & 2 deletions content/guides/standard-html-reactivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Standard HTML Reactivity"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/guides/standard-html-reactivity.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Standard HTML Reactivity
Expand Down
4 changes: 2 additions & 2 deletions content/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Go Library API Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/api-reference.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Go Library API Reference
Expand Down
4 changes: 2 additions & 2 deletions content/reference/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Authentication Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/authentication.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Authentication Reference
Expand Down
4 changes: 2 additions & 2 deletions content/reference/client-attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Client Attributes Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/client-attributes.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Client Attributes Reference
Expand Down
4 changes: 2 additions & 2 deletions content/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "LiveTemplate Configuration Guide"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/CONFIGURATION.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# LiveTemplate Configuration Guide
Expand Down
32 changes: 30 additions & 2 deletions content/reference/controller-pattern.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Controller+State Pattern Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/controller-pattern.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Controller+State Pattern Reference
Expand Down Expand Up @@ -147,6 +147,32 @@ func (c *TodoController) Mount(state TodoState, ctx *livetemplate.Context) (Todo
- Set up computed fields
- Initialize state based on user context

**Guarding side effects per connect kind:** Mount runs on HTTP GET, HTTP POST actions, WebSocket new-connect, and WebSocket reconnect. Use `ctx.IsInitialMount()` to limit one-time setup (e.g. starting a background goroutine) to initial page loads, and `ctx.IsReconnect()` to detect a WebSocket reconnect that restored persisted state:

```go
func (c *TodoController) Mount(state TodoState, ctx *livetemplate.Context) (TodoState, error) {
if ctx.IsInitialMount() {
// Only on initial HTTP GET — not POST actions, not WS connects.
state.Loading = true
go c.warmCacheFor(ctx.UserID())
}
return state, nil
}
```

```go
func (c *ChatController) OnConnect(state ChatState, ctx *livetemplate.Context) (ChatState, error) {
if ctx.IsReconnect() {
// Network blipped — re-announce presence, skip re-fetches the prior
// connection already completed.
state.SystemMessages = append(state.SystemMessages, "[reconnected]")
}
return state, nil
}
```

The older `ctx.Action() == ""` idiom still works (it returns true for GET, internal navigate POSTs, and WS connects/reconnects), but the new helpers disambiguate the four lifecycle paths and make intent obvious to readers.

### OnConnect

Called when a WebSocket connection is established:
Expand All @@ -170,6 +196,8 @@ func (c *TodoController) OnConnect(state TodoState, ctx *livetemplate.Context) (
- Start background jobs
- Subscribe to real-time data feeds

**Heads-up — `ctx.IsReconnect()` on the first WS:** When a browser does the normal flow (HTTP GET → server-renders → WebSocket connects), the framework persists state at the end of the HTTP-path Mount, then *restores* that state when the WebSocket opens. The WS-path `OnConnect` therefore sees `ctx.IsReconnect() == true` even though no prior WebSocket connection ever existed. If your `OnConnect` needs to distinguish "brand-new session" from "WS resumed after a blip", pair `IsReconnect()` with `IsNewConnect()` or gate on per-session state. See the `IsReconnect` godoc for the full semantics.

### OnDisconnect

Called when a WebSocket connection is closed:
Expand Down
4 changes: 2 additions & 2 deletions content/reference/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Error Handling Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/error-handling.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Error Handling Reference
Expand Down
4 changes: 2 additions & 2 deletions content/reference/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Current Limitations"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/current-limitations.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Current Limitations
Expand Down
28 changes: 22 additions & 6 deletions content/reference/navigate.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Navigate Action Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/navigate.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Navigate Action Reference
Expand Down Expand Up @@ -50,20 +50,36 @@ If the WebSocket is not OPEN, the client falls through to fetch-based navigation

Mount runs on every HTTP request, every WS connect, AND every `__navigate__`. Crucially, **inside Mount, a `__navigate__` re-run is indistinguishable from a connect-time Mount** — the dispatch loop deliberately rebinds `ctx.Action()` to `""` for navigate so handlers don't have to special-case it. (Grep `mount.go` for `WithAction("") // ctx.Action()=="" matches connect-time Mount`.)

That means the standard `if ctx.Action() == "" { ... }` guard from the controller-pattern docs filters out form POSTs but does **not** filter out navigate re-mounts. If you have side effects that must fire exactly once per session (analytics page-view, audit log, expensive bootstrap), gate them on per-session state, not on `ctx.Action()`:
That means the standard `if ctx.Action() == "" { ... }` guard from the controller-pattern docs filters out form POSTs but does **not** filter out navigate re-mounts — it still fires on each `__navigate__`. There are two ways to handle one-time side effects (analytics page-view, audit log, expensive bootstrap):

**Preferred — `ctx.IsInitialMount()`:** Returns true only for the initial HTTP GET, false for WS new-connects, reconnects, *and* `__navigate__` re-mounts (which dispatch through the WS event loop as an action, not as a GET). Side effects fire exactly once per initial page load:

```go
func (c *Controller) Mount(state State, ctx *livetemplate.Context) (State, error) {
if ctx.Action() == "" && !state.PageViewTracked {
if ctx.IsInitialMount() {
c.analytics.TrackPageView(ctx.UserID())
state.PageViewTracked = true
}
state.Filter = ctx.GetString("filter")
return state, nil
}
```

State persists across navigate re-mounts within the same session, so the `PageViewTracked` flag survives. This pattern is the recommended workaround until a first-class "is this the initial mount" signal lands; see issue [#346](https://github.com/livetemplate/livetemplate/issues/346) for the related discussion on `BroadcastAction` semantics inside navigate Mount.
**Fallback — `ctx.Action() == ""` + persist flag:** If you still use the older idiom (which is true for GETs, WS connects, *and* navigate re-mounts), gate side effects on per-session state so they don't fire repeatedly:

```go
if ctx.Action() == "" && !state.PageViewTracked {
c.analytics.TrackPageView(ctx.UserID())
state.PageViewTracked = true
}
```

**`ConnectKind` behavior during navigate re-mounts:** The dispatch loop applies `WithAction("")` to the WS connection's lifecycle Context for `__navigate__`, which shallow-copies the Context and preserves `connectKind`. So inside a navigate re-mount:

- `ctx.IsInitialMount()` is always **false** (the GET fired earlier, with a different Context).
- `ctx.IsNewConnect()` reflects the *original* WS connect-time classification — true if the underlying WS was the first connect for this group, false otherwise.
- `ctx.IsReconnect()` likewise reflects the original WS classification — true if state was restored when the WS first connected.

Only `IsInitialMount()` is guaranteed false inside a navigate re-mount; the other two helpers report the underlying WS's connect-kind, not a navigate-specific value.

### Read query params from `ctx`

Expand Down
4 changes: 2 additions & 2 deletions content/reference/progressive-complexity.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Progressive Complexity Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/progressive-complexity-reference.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Progressive Complexity Reference
Expand Down
4 changes: 2 additions & 2 deletions content/reference/pubsub.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "PubSub Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/pubsub.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# PubSub Reference
Expand Down
4 changes: 2 additions & 2 deletions content/reference/server-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Server Actions Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/server-actions.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Server Actions Reference
Expand Down
6 changes: 3 additions & 3 deletions content/reference/session.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Session Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/session.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Session Reference
Expand Down Expand Up @@ -45,7 +45,7 @@ In this example, `Filter` and `Page` survive page refreshes because they are per

**Mount() lifecycle:** `Mount()` is called on every HTTP request (GET and POST) and every WebSocket connect (new and reconnect). It receives the current state (with persisted fields restored, ephemeral fields at zero value) and returns refreshed state. This ensures data is always fresh from the database. Keep Mount cheap -- it runs on every request.

**Mount on POST:** Since Mount runs before actions on HTTP POST, it must populate ephemeral fields (e.g., `state.Items = db.GetItems(state.Filter)`). Persisted fields like `Filter` and `Page` are already restored from the SessionStore before Mount receives the state. Guard side effects with `ctx.Action() == ""` to restrict them to page loads.
**Mount on POST:** Since Mount runs before actions on HTTP POST, it must populate ephemeral fields (e.g., `state.Items = db.GetItems(state.Filter)`). Persisted fields like `Filter` and `Page` are already restored from the SessionStore before Mount receives the state. Guard side effects with `ctx.IsInitialMount()` (preferred — true only on HTTP GET) or the older `ctx.Action() == ""` (true on GET, internal navigate POSTs, and WS connects/reconnects).

### State Persistence Matrix

Expand Down
4 changes: 2 additions & 2 deletions content/reference/template-support-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "LiveTemplate Go Template Support Matrix"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/template-support-matrix.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# LiveTemplate Go Template Support Matrix
Expand Down
4 changes: 2 additions & 2 deletions content/reference/uploads.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: "Upload Reference"
source_repo: "https://github.com/livetemplate/livetemplate"
source_path: "docs/references/uploads.md"
source_ref: "v0.9.0"
source_commit: "5b9a7cb8cb53d0ad75119ff54f70b6fdd85e05bd"
source_ref: "v0.9.1"
source_commit: "e9a44d16e52d68472e399a5a68ad8713179e9c7f"
---

# Upload Reference
Expand Down
Loading