Skip to content

Commit 71b867d

Browse files
committed
docs(go): flesh out webview + forge, expand sidebar nav
webview - CDP client overview + connect-to-Chrome quickstart - ActionSequence fluent builder with short-circuit-on-fail example - ConsoleWatcher + ExceptionWatcher streaming patterns - AngularHelper — Zone.js stability, ng router, ng-model bypass - Service Register + ServiceOptions example - Low-level CDP client escape hatch forge - Two constructors: explicit URL+token vs config-driven - Generic Resource[T, C, U] CRUD parameterisation example - Three pagination shapes — ListPage, ListAll, ListIter (Go 1.23 range-over-func) - Service Register + ServiceOptions example Sidebar (astro.config.mjs) - New "Packages — content" group at top of nav surfaces the five fleshed-out pages (store/io/process/webview/forge) ahead of the seven stubs that were already linked - New "Packages — index" group (collapsed) lists the remaining 26 stub pages so the full ecosystem scope is visible without cluttering the active demo path - Each promoted page has working code examples + cross-links Co-Authored-By: Virgil <virgil@lethean.io>
1 parent 8bccbeb commit 71b867d

3 files changed

Lines changed: 288 additions & 10 deletions

File tree

astro.config.mjs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,16 @@ export default defineConfig({
5151
],
5252
},
5353
{
54-
label: 'Packages',
54+
// Recently fleshed-out — these have real content + examples
55+
// today. Promoted to the top of the package list so demos
56+
// can jump straight in without hunting through stubs.
57+
label: 'Packages — content',
5558
items: [
59+
{ label: 'store', slug: 'go/store' },
60+
{ label: 'io', slug: 'go/io' },
61+
{ label: 'process', slug: 'go/process' },
62+
{ label: 'webview', slug: 'go/webview' },
63+
{ label: 'forge', slug: 'go/forge' },
5664
{ label: 'agent', slug: 'go/agent' },
5765
{ label: 'mcp', slug: 'go/mcp' },
5866
{ label: 'miner', slug: 'go/miner' },
@@ -62,6 +70,41 @@ export default defineConfig({
6270
{ label: 'tenant', slug: 'go/tenant' },
6371
],
6472
},
73+
{
74+
// Stub pages — `go get` resolves them, human-facing content
75+
// fills in as each package converges. Listed so the full
76+
// ecosystem scope is visible in the nav.
77+
label: 'Packages — index',
78+
collapsed: true,
79+
items: [
80+
{ label: 'ai', slug: 'go/ai' },
81+
{ label: 'ansible', slug: 'go/ansible' },
82+
{ label: 'api', slug: 'go/api' },
83+
{ label: 'build', slug: 'go/build' },
84+
{ label: 'cgo', slug: 'go/cgo' },
85+
{ label: 'cli', slug: 'go/cli' },
86+
{ label: 'config', slug: 'go/config' },
87+
{ label: 'container', slug: 'go/container' },
88+
{ label: 'crypt', slug: 'go/crypt' },
89+
{ label: 'devops', slug: 'go/devops' },
90+
{ label: 'dns', slug: 'go/dns' },
91+
{ label: 'git', slug: 'go/git' },
92+
{ label: 'gui', slug: 'go/gui' },
93+
{ label: 'html', slug: 'go/html' },
94+
{ label: 'i18n', slug: 'go/i18n' },
95+
{ label: 'ide', slug: 'go/ide' },
96+
{ label: 'inference', slug: 'go/inference' },
97+
{ label: 'log', slug: 'go/log' },
98+
{ label: 'ml', slug: 'go/ml' },
99+
{ label: 'mlx', slug: 'go/mlx' },
100+
{ label: 'netops', slug: 'go/netops' },
101+
{ label: 'orm', slug: 'go/orm' },
102+
{ label: 'p2p', slug: 'go/p2p' },
103+
{ label: 'rag', slug: 'go/rag' },
104+
{ label: 'scm', slug: 'go/scm' },
105+
{ label: 'ws', slug: 'go/ws' },
106+
],
107+
},
65108
],
66109
}),
67110
],

src/content/docs/go/forge.mdx

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ head:
1212
content: 'dappco.re/go/forge https://github.com/dappcore/go-forge https://github.com/dappcore/go-forge/tree/main{/dir} https://github.com/dappcore/go-forge/blob/main{/dir}/{file}#L{line}'
1313
---
1414

15-
Forgejo client — repo, branch, hook, runner orchestration. Built on the [`core/go`](/go/) primitives.
15+
Typed HTTP client for Forgejo (and Gitea) — repos, branches, issues, pull
16+
requests, hooks, runners. Generic `Resource[T, C, U]` and paginated
17+
helpers cover the long tail of CRUD shapes without hand-writing each
18+
endpoint. Built on [`core/go`](/go/) — every constructor that touches
19+
config returns a [`Result`](/go/result/).
1620

1721
## Install
1822

@@ -26,7 +30,100 @@ go get dappco.re/go/forge@latest
2630
import "dappco.re/go/forge"
2731
```
2832

29-
## Status
33+
## Quick start
3034

31-
Page in flight — content fills in as the package converges. Source of truth
32-
today is the README and inline docstrings in the repo.
35+
Two constructors — explicit URL+token or auto-pulled from config flags:
36+
37+
```go
38+
// Explicit
39+
fg := forge.NewForge("https://forge.lthn.sh", os.Getenv("FORGEJO_TOKEN"))
40+
41+
// Config-driven (flags first, env fallback)
42+
r := forge.NewForgeFromConfig("--forge-url", "--forge-token")
43+
if !r.OK { return r }
44+
fg := r.Value.(*forge.Forge)
45+
```
46+
47+
`Forge` wraps a `*Client` plus typed Resource handles for every standard
48+
endpoint group. Direct HTTP access stays available via `fg.Client()` for
49+
calls the typed surface doesn't cover yet.
50+
51+
## Generic resources
52+
53+
`Resource[T, C, U]` parameterises CRUD over three types — the read shape,
54+
the create shape, and the update shape. The package exports pre-bound
55+
resources for the common Forgejo objects (repos, issues, PRs, hooks,
56+
runners, …); custom integrations can spin their own:
57+
58+
```go
59+
type MyKind struct { ID int; Name string }
60+
type CreateMyKind struct { Name string }
61+
type UpdateMyKind struct { Name *string }
62+
63+
r := forge.NewResource[MyKind, CreateMyKind, UpdateMyKind](
64+
fg.Client(),
65+
"/api/v1/orgs/{org}/my-kinds",
66+
)
67+
68+
items, _ := r.List(ctx, map[string]string{"org": "dappcore"})
69+
created, _ := r.Create(ctx, CreateMyKind{Name: "shiny"})
70+
```
71+
72+
## Pagination — three shapes, one signature
73+
74+
Forgejo paginates everything. The helpers give callers a choice of memory
75+
profile:
76+
77+
```go
78+
// One page at a time — caller drives the loop
79+
page, _ := forge.ListPage[Repo](ctx, fg.Client(), "/repos/search", q, forge.ListOptions{
80+
Page: 1,
81+
PerPage: 50,
82+
})
83+
84+
// All pages collected — slurp into memory
85+
all, _ := forge.ListAll[Repo](ctx, fg.Client(), "/repos/search", q)
86+
87+
// Streaming iterator — Go 1.23+ range-over-func
88+
for repo, err := range forge.ListIter[Repo](ctx, fg.Client(), "/repos/search", q) {
89+
if err != nil { return err }
90+
fmt.Println(repo.FullName)
91+
}
92+
```
93+
94+
`ListIter` is the right default for long results — it fetches pages on
95+
demand without holding the whole set in memory.
96+
97+
## Service registration
98+
99+
The canonical `core/go` Service pattern — register once on a Core and
100+
every consumer reaches Forgejo through `c.Action("forge/...")`:
101+
102+
```go
103+
c := core.New(core.Options{})
104+
105+
if r := forge.Register(c); !r.OK { return r }
106+
107+
// With options
108+
svc := forge.NewService(forge.ServiceOptions{
109+
URL: "https://forge.lthn.sh",
110+
Token: os.Getenv("FORGEJO_TOKEN"),
111+
})
112+
if r := svc(c); !r.OK { return r }
113+
```
114+
115+
The Service constructor reads config + env in the same order as
116+
`NewForgeFromConfig` so a single Core instance has one consistent Forge
117+
binding.
118+
119+
## Sibling packages
120+
121+
- [`go/scm`](/go/scm/) — Git operations on the repos forge serves
122+
- [`go/process`](/go/process/) — supervise long-running runners forge
123+
dispatches
124+
- [`go/webview`](/go/webview/) — the same Result-returning Service shape
125+
for browser automation
126+
127+
## Source
128+
129+
[`github.com/dappcore/go-forge`](https://github.com/dappcore/go-forge) — full source, issues, and releases.

src/content/docs/go/webview.mdx

Lines changed: 143 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: webview
3-
description: WebView runtime — bridge, codegen, transport.
3+
description: Chrome DevTools Protocol client — browser automation, testing, scraping.
44
head:
55
- tag: meta
66
attrs:
@@ -12,7 +12,13 @@ head:
1212
content: 'dappco.re/go/webview https://github.com/dappcore/go-webview https://github.com/dappcore/go-webview/tree/main{/dir} https://github.com/dappcore/go-webview/blob/main{/dir}/{file}#L{line}'
1313
---
1414

15-
WebView runtime — bridge, codegen, transport. Built on the [`core/go`](/go/) primitives.
15+
Chrome DevTools Protocol client for browser automation. Connects to an
16+
externally managed Chrome or Chromium instance running with
17+
`--remote-debugging-port=9222` and gives you navigation, DOM queries, click
18+
+ type actions, console capture, JavaScript evaluation, screenshots,
19+
multi-tab support, viewport emulation, and a fluent `ActionSequence`
20+
builder. Built on [`core/go`](/go/) — every constructor returns a
21+
[`Result`](/go/result/).
1622

1723
## Install
1824

@@ -26,7 +32,139 @@ go get dappco.re/go/webview@latest
2632
import "dappco.re/go/webview"
2733
```
2834

29-
## Status
35+
## Quick start
3036

31-
Page in flight — content fills in as the package converges. Source of truth
32-
today is the README and inline docstrings in the repo.
37+
Launch Chrome with the remote debugging port open, then point a Webview
38+
at it:
39+
40+
```bash
41+
chrome --remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile
42+
```
43+
44+
```go
45+
r := webview.New(webview.WithDebugURL("http://localhost:9222"))
46+
if !r.OK { return r }
47+
wv := r.Value.(*webview.Webview)
48+
defer wv.Close()
49+
50+
wv.Navigate("https://example.com")
51+
wv.Click("#submit")
52+
wv.Type("#input", "search term")
53+
54+
png, _ := wv.Screenshot()
55+
```
56+
57+
## ActionSequence — fluent chain
58+
59+
For test scripts and scrape recipes, `ActionSequence` strings calls together
60+
and short-circuits on first failure:
61+
62+
```go
63+
seq := webview.NewActionSequence()
64+
65+
r := seq.
66+
Navigate("https://example.com/login").
67+
Type("#username", "alice").
68+
Type("#password", "s3cret").
69+
Click("button[type=submit]").
70+
WaitFor("#dashboard").
71+
Screenshot("dashboard.png").
72+
Run(wv)
73+
74+
if !r.OK { return r }
75+
```
76+
77+
Each step records its outcome so a failed sequence reports the exact step
78+
that broke rather than a generic "automation failed".
79+
80+
## Watchers
81+
82+
Two background watchers attach to a `*Webview` and stream
83+
async-but-relevant events without polling:
84+
85+
```go
86+
con := webview.NewConsoleWatcher(wv)
87+
con.Start(ctx)
88+
go func() {
89+
for msg := range con.Messages() {
90+
log.Printf("[%s] %s", msg.Level, msg.Text)
91+
}
92+
}()
93+
94+
ex := webview.NewExceptionWatcher(wv)
95+
ex.Start(ctx)
96+
go func() {
97+
for e := range ex.Exceptions() {
98+
log.Printf("page exception: %v", e)
99+
}
100+
}()
101+
```
102+
103+
Useful for catching JS errors during smoke tests, or capturing
104+
`console.log` output from instrumented frontends.
105+
106+
## Angular helpers
107+
108+
When the page is an Angular app, `AngularHelper` wires in the framework's
109+
internals so tests can wait for Zone.js stability, drive the router, and
110+
read component state directly:
111+
112+
```go
113+
ng := webview.NewAngularHelper(wv)
114+
115+
ng.WaitForStability(ctx) // Zone.js settled
116+
ng.NavigateByUrl("/dashboard") // ng router
117+
ng.SetNgModel("input#email", "a@b") // bypass typing
118+
val, _ := ng.GetComponentField("AppComponent", "user.id")
119+
```
120+
121+
Skips race conditions that vanilla CDP tests hit when the framework's
122+
microtasks haven't drained yet.
123+
124+
## Service registration
125+
126+
The package ships the canonical `core/go` Service pattern:
127+
128+
```go
129+
c := core.New(core.Options{})
130+
131+
if r := webview.Register(c); !r.OK { return r }
132+
133+
// Or with explicit options
134+
svc := webview.NewService(webview.ServiceOptions{
135+
DebugURL: "http://localhost:9222",
136+
})
137+
if r := svc(c); !r.OK { return r }
138+
```
139+
140+
Consumers reach the Webview through `c.Action("webview/...")` so a test
141+
binary, a scrape worker, and a CI dispatcher all share one entry point.
142+
143+
## Low-level CDP client
144+
145+
If you need to send raw CDP commands, `NewCDPClient` exposes the protocol
146+
directly without the high-level wrapper:
147+
148+
```go
149+
r := webview.NewCDPClient("http://localhost:9222")
150+
if !r.OK { return r }
151+
cdp := r.Value.(*webview.CDPClient)
152+
153+
cdp.Send("Network.enable", nil)
154+
cdp.Send("Page.navigate", map[string]any{"url": "https://example.com"})
155+
```
156+
157+
The high-level `Webview` is built on top of this client, so anything it
158+
does, you can do too.
159+
160+
## Sibling packages
161+
162+
- [`go/process`](/go/process/) — supervise the Chrome process that
163+
Webview connects to
164+
- [`go/io`](/go/io/) — persist screenshots, scraped payloads
165+
- [`go/forge`](/go/forge/) — the same Result-returning Service shape for
166+
the Forgejo HTTP client
167+
168+
## Source
169+
170+
[`github.com/dappcore/go-webview`](https://github.com/dappcore/go-webview) — full source, issues, and releases.

0 commit comments

Comments
 (0)