Skip to content

Commit 6dc6250

Browse files
committed
feat: Add Router Analytics Plugin
1 parent 4e89987 commit 6dc6250

File tree

6 files changed

+597
-0
lines changed

6 files changed

+597
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Router Analytics Plugin
2+
3+
The **Router Analytics** plugin tracks page-to-page transitions and predicts likely next routes. It can also emit **prefetch hints** for the most probable next pages, so your app can warm up data/assets.
4+
5+
> This is a **built‑in plugin**. It doesn’t change your routing— it observes navigations and learns probabilities.
6+
7+
## Features
8+
9+
* Records transitions between normalized routes (e.g. `/posts``/settings`).
10+
* Exposes **transition probabilities** and **top‑N predictions**.
11+
* Optional **prefetch hints** over a netcode channel (browser / Wasm builds).
12+
* Pluggable route normalization.
13+
14+
## Quick Start
15+
16+
Register the plugin at boot:
17+
18+
```go
19+
import (
20+
core "github.com/rfwlab/rfw/v1/core"
21+
routeranalytics "github.com/rfwlab/rfw/v1/plugins/routeranalytics"
22+
)
23+
24+
func main() {
25+
core.RegisterPlugin(routeranalytics.New(routeranalytics.Options{
26+
// optional: customize behavior
27+
// PrefetchLimit: 3, // number of next routes to hint
28+
// PrefetchThreshold: 0.25, // drop hints below this probability
29+
// Channel: "RouterPrefetch", // netcode channel name
30+
// Normalize: routeranalytics.NormalizePath, // default normalization
31+
}))
32+
}
33+
```
34+
35+
The plugin automatically hooks into the app router and learns from each navigation.
36+
37+
## Example (predict next routes)
38+
39+
```go
40+
// Get ordered probabilities for what users do next from "/posts"
41+
probs := routeranalytics.TransitionProbabilities("/posts")
42+
for _, p := range probs {
43+
// p.To, p.Count, p.Probability
44+
}
45+
46+
// Ask for the top 2 most likely next routes
47+
top2 := routeranalytics.MostLikelyNext("/posts", 2)
48+
```
49+
50+
If `PrefetchLimit` > 0, each navigation will enqueue prefetch hints for predicted routes with probability ≥ `PrefetchThreshold` (browser/Wasm builds only).
51+
52+
## How It Works
53+
54+
* **Normalization** (default): trims whitespace, removes `?query` and `#hash`, and ensures a **leading slash**.
55+
* **Learning**: each navigation updates counters for `from → to` and totals per `from`.
56+
* **Probabilities**: computed as `count(from→to) / total(from)` and returned **sorted** by probability (then alphabetically by `to`).
57+
* **Prefetch**: in Wasm builds, predicted routes are sent once over a netcode client on the configured channel.
58+
59+
## API Reference
60+
61+
### Types
62+
63+
```go
64+
type Options struct {
65+
Normalize func(string) string // normalize a path before tracking
66+
PrefetchLimit int // number of routes to prefetch (<=0 disables)
67+
PrefetchThreshold float64 // drop hints below this probability (<=0 → 0.2)
68+
Channel string // netcode channel (default "RouterPrefetch")
69+
}
70+
71+
type TransitionProbability struct {
72+
From string
73+
To string
74+
Count int
75+
Probability float64
76+
}
77+
```
78+
79+
### Constructors & Plugin hooks
80+
81+
```go
82+
func New(opts Options) *Plugin
83+
func (p *Plugin) Name() string // "routeranalytics"
84+
func (p *Plugin) Build(json.RawMessage) error // no-op
85+
func (p *Plugin) Install(a *core.App) // attaches to router
86+
```
87+
88+
### Instance methods
89+
90+
```go
91+
func (p *Plugin) TransitionProbabilities(from string) []TransitionProbability
92+
func (p *Plugin) MostLikelyNext(from string, limit int) []TransitionProbability
93+
func (p *Plugin) Reset()
94+
```
95+
96+
### Package helpers (use the latest installed instance)
97+
98+
```go
99+
func TransitionProbabilities(from string) []TransitionProbability
100+
func MostLikelyNext(from string, limit int) []TransitionProbability
101+
func Reset()
102+
```
103+
104+
### Utilities
105+
106+
```go
107+
// Default normalization: trim, strip query/hash, ensure leading slash.
108+
func NormalizePath(path string) string
109+
```
110+
111+
## Defaults
112+
113+
* `Normalize`: `NormalizePath`
114+
* `PrefetchLimit`: `3` (set `< 0` to disable, `0` → `3`)
115+
* `PrefetchThreshold`: `0.2` if `<= 0`
116+
* `Channel`: `"RouterPrefetch"`

docs/articles/sidebar.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@
200200
"title": "Pages",
201201
"path": "plugins/pages.md"
202202
},
203+
{
204+
"title": "Router Analytics",
205+
"path": "plugins/router-analytics.md"
206+
},
203207
{
204208
"title": "SEO",
205209
"path": "plugins/seo.md"

0 commit comments

Comments
 (0)