fix(deps): migrate to chromedp 0.19 and drop the cdproto replace

Update chromedp to v0.19.1 and cdproto to v0.157.4, port the browser, reader and login code to the generic Action API, group both modules in Renovate, and move the Docker build to Go 1.27.
This commit is contained in:
2026-10-05 10:32:22 +01:00
parent 5d945156ba
commit 956aa3c0cb
9 changed files with 67 additions and 91 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
# Build stage # Build stage
FROM golang:1.26-alpine AS build FROM golang:1.27-alpine AS build
WORKDIR /src WORKDIR /src
COPY go.mod go.sum ./ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
+3 -12
View File
@@ -1,24 +1,18 @@
module github.com/lukaszraczylo/mcp-readitall module github.com/lukaszraczylo/mcp-readitall
go 1.26.4 go 1.27
require ( require (
github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2 github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2
github.com/chromedp/cdproto v0.157.2 github.com/chromedp/cdproto v0.157.4
github.com/chromedp/chromedp v0.16.0 github.com/chromedp/chromedp v0.19.1
github.com/modelcontextprotocol/go-sdk v1.8.0 github.com/modelcontextprotocol/go-sdk v1.8.0
github.com/stretchr/testify v1.12.1 github.com/stretchr/testify v1.12.1
) )
require ( require (
github.com/JohannesKaufmann/dom v0.3.1 // indirect github.com/JohannesKaufmann/dom v0.3.1 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/go-json-experiment/json v0.0.0-20260820222146-c27c302e5fc3 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/google/jsonschema-go v0.4.3 // indirect github.com/google/jsonschema-go v0.4.3 // indirect
github.com/orisano/pixelmatch v0.0.0-20230914042517-fa304d1dc785 // indirect
github.com/segmentio/asm v1.2.1 // indirect github.com/segmentio/asm v1.2.1 // indirect
github.com/segmentio/encoding v0.5.4 // indirect github.com/segmentio/encoding v0.5.4 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
@@ -29,6 +23,3 @@ require (
golang.org/x/sys v0.48.0 // indirect golang.org/x/sys v0.48.0 // indirect
golang.org/x/time v0.16.0 // indirect golang.org/x/time v0.16.0 // indirect
) )
// chromedp v0.16 builds against this cdproto; the v0.157 tag changed the input API.
replace github.com/chromedp/cdproto => github.com/chromedp/cdproto v0.0.0-20260714215040-dc233986426f
+4 -19
View File
@@ -2,32 +2,18 @@ github.com/JohannesKaufmann/dom v0.3.1 h1:J16l9JAHWgkFPR3VIPbQ1gvS0cWab6laK1q7PF
github.com/JohannesKaufmann/dom v0.3.1/go.mod h1:BZPkf8ZeYrBgABjwJn9iiKt8aiCtkxpHkevms+Yp2DE= github.com/JohannesKaufmann/dom v0.3.1/go.mod h1:BZPkf8ZeYrBgABjwJn9iiKt8aiCtkxpHkevms+Yp2DE=
github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2 h1:XFJZFWESIWlUEHHjzBuv8RvrtCWnSGlimEX17ysSDb8= github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2 h1:XFJZFWESIWlUEHHjzBuv8RvrtCWnSGlimEX17ysSDb8=
github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2/go.mod h1:BHWO8lJzttJLqwuV8Rb1B3OG2OSzLbssZDI1FRg2eAA= github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2/go.mod h1:BHWO8lJzttJLqwuV8Rb1B3OG2OSzLbssZDI1FRg2eAA=
github.com/chromedp/cdproto v0.0.0-20260714215040-dc233986426f h1:0Z1zcSLEmnj2c2CmJYBqewtS6pxhB39bNWUSEUAWjgk= github.com/chromedp/cdproto v0.157.4 h1:UleIu3RHfaQmhE0ri9GpCbHrGpe0HgV55HVhzhPWglI=
github.com/chromedp/cdproto v0.0.0-20260714215040-dc233986426f/go.mod h1:RwFsSODCtFExll+GhHM6R92SARHR3Z3oipaxLHj46C0= github.com/chromedp/cdproto v0.157.4/go.mod h1:scNPhJ/A4T8BVkyR5k2Uocvoju3iBRZS4cg3uMlxuMk=
github.com/chromedp/chromedp v0.16.0 h1:rOO4deOm4CbZgBCa8mD9g2rDyIoNs0BkgvNrlbp5ouk= github.com/chromedp/chromedp v0.19.1 h1:OAf0ukr4nC5LIwaYEWIv7JYXlpZIZt6ZSDsYXCdjGlc=
github.com/chromedp/chromedp v0.16.0/go.mod h1:rbuGKFT1vMcFcFqKfPIO1GpX/N+2s8onm2qMxZLbU5U= github.com/chromedp/chromedp v0.19.1/go.mod h1:4Rs9XtapAMgXxg0s1PpixyQHf37kdnSdu2ov5G4FsZ0=
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
github.com/go-json-experiment/json v0.0.0-20260820222146-c27c302e5fc3 h1:UADEEmDKgfXbtnGJZ97beY5XLo9ZechG1nlU4KnRrkE=
github.com/go-json-experiment/json v0.0.0-20260820222146-c27c302e5fc3/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0= github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0=
github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/modelcontextprotocol/go-sdk v1.8.0 h1:KIvahhYqwtbeniWVPs3TcXEA7b8jEtwfBpOTAI+Urx4= github.com/modelcontextprotocol/go-sdk v1.8.0 h1:KIvahhYqwtbeniWVPs3TcXEA7b8jEtwfBpOTAI+Urx4=
github.com/modelcontextprotocol/go-sdk v1.8.0/go.mod h1:dL7u98E/zjJTGzEq+j30jQ8K2k1mb6LeAH4inEcSGts= github.com/modelcontextprotocol/go-sdk v1.8.0/go.mod h1:dL7u98E/zjJTGzEq+j30jQ8K2k1mb6LeAH4inEcSGts=
github.com/orisano/pixelmatch v0.0.0-20230914042517-fa304d1dc785 h1:J1//5K/6QF10cZ59zLcVNFGmBfiSrH8Cho/lNrViK9s=
github.com/orisano/pixelmatch v0.0.0-20230914042517-fa304d1dc785/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sebdah/goldie/v2 v2.8.0 h1:dZb9wR8q5++oplmEiJT+U/5KyotVD+HNGCAc5gNr8rc= github.com/sebdah/goldie/v2 v2.8.0 h1:dZb9wR8q5++oplmEiJT+U/5KyotVD+HNGCAc5gNr8rc=
@@ -52,7 +38,6 @@ golang.org/x/oauth2 v0.37.0 h1:JUlcxA8oAtauLfiH8FX2/FkAWHAdi0QtGCGc+hofE98=
golang.org/x/oauth2 v0.37.0/go.mod h1:IxwZNxUULJmpBFf9K/9NTMSIfZZuvuTy1gGxhigP/58= golang.org/x/oauth2 v0.37.0/go.mod h1:IxwZNxUULJmpBFf9K/9NTMSIfZZuvuTy1gGxhigP/58=
golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE= golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE=
+3 -5
View File
@@ -66,7 +66,7 @@ func (b *Browser) ensureAllocator() (context.Context, error) {
b.allocCtx, b.allocCancel = chromedp.NewExecAllocator(context.Background(), opts...) b.allocCtx, b.allocCancel = chromedp.NewExecAllocator(context.Background(), opts...)
browserCtx, cancel := chromedp.NewContext(b.allocCtx) browserCtx, cancel := chromedp.NewContext(b.allocCtx)
if err := chromedp.Run(browserCtx, chromedp.Navigate("about:blank")); err != nil { if err := chromedp.Do(browserCtx, chromedp.Navigate("about:blank")); err != nil {
b.startErr = fmt.Errorf("warm up browser: %w", err) b.startErr = fmt.Errorf("warm up browser: %w", err)
cancel() cancel()
return return
@@ -144,10 +144,8 @@ func (b *Browser) NewContext(parentCtx context.Context, statePath string) (conte
// the first step of a fresh login (otherwise stale session cookies from // the first step of a fresh login (otherwise stale session cookies from
// a previous attempt can mask the new login's success). // a previous attempt can mask the new login's success).
func ClearAllCookies(ctx context.Context) error { func ClearAllCookies(ctx context.Context) error {
return chromedp.Run(ctx, chromedp.ActionFunc(func(ctx context.Context) error { _, err := chromedp.Call(ctx, network.ClearBrowserCookies, cdp.Empty{})
target := chromedp.FromContext(ctx).Target return err
return network.ClearBrowserCookies().Do(cdp.WithExecutor(ctx, target))
}))
} }
// NewHeadedContext spawns a *separate* Chromium process with a visible // NewHeadedContext spawns a *separate* Chromium process with a visible
+18 -25
View File
@@ -7,7 +7,6 @@ import (
"net/url" "net/url"
"os" "os"
"strings" "strings"
"time"
"github.com/chromedp/cdproto/cdp" "github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/network" "github.com/chromedp/cdproto/network"
@@ -76,10 +75,8 @@ func ApplyStorageStateCookies(ctx context.Context, statePath string) error {
return nil return nil
} }
return chromedp.Run(ctx, chromedp.ActionFunc(func(ctx context.Context) error { _, err = chromedp.Call(ctx, network.SetCookies, network.SetCookiesParams{Cookies: cookies})
target := chromedp.FromContext(ctx).Target return err
return network.SetCookies(cookies).Do(cdp.WithExecutor(ctx, target))
}))
} }
// ApplyLocalStorageOnCurrentOrigin sets every localStorage entry that // ApplyLocalStorageOnCurrentOrigin sets every localStorage entry that
@@ -99,8 +96,8 @@ func ApplyLocalStorageOnCurrentOrigin(ctx context.Context, statePath string) err
return nil return nil
} }
var currentURL string currentURL, err := chromedp.Run(ctx, chromedp.Location())
if err := chromedp.Run(ctx, chromedp.Location(&currentURL)); err != nil { if err != nil {
return fmt.Errorf("read current origin: %w", err) return fmt.Errorf("read current origin: %w", err)
} }
currentOrigin := normalizeOrigin(currentURL) currentOrigin := normalizeOrigin(currentURL)
@@ -123,7 +120,8 @@ func ApplyLocalStorageOnCurrentOrigin(ctx context.Context, statePath string) err
return nil return nil
} }
return chromedp.Run(ctx, chromedp.Evaluate(buildLocalStorageScript(entries), nil)) _, err = chromedp.Run(ctx, chromedp.Evaluate[chromedp.Void](buildLocalStorageScript(entries)))
return err
} }
// CaptureStorageState reads every cookie set on the current target and // CaptureStorageState reads every cookie set on the current target and
@@ -138,8 +136,8 @@ func CaptureStorageState(ctx context.Context, statePath string) error {
} }
// 2) Current origin + localStorage // 2) Current origin + localStorage
var currentURL string currentURL, err := chromedp.Run(ctx, chromedp.Location())
if err := chromedp.Run(ctx, chromedp.Location(&currentURL)); err != nil { if err != nil {
return fmt.Errorf("read location: %w", err) return fmt.Errorf("read location: %w", err)
} }
origin := normalizeOrigin(currentURL) origin := normalizeOrigin(currentURL)
@@ -182,14 +180,11 @@ func CaptureStorageState(ctx context.Context, statePath string) error {
// captureCDPCookies asks the current target for its full cookie list via // captureCDPCookies asks the current target for its full cookie list via
// the network domain. // the network domain.
func captureCDPCookies(ctx context.Context) ([]*network.Cookie, error) { func captureCDPCookies(ctx context.Context) ([]*network.Cookie, error) {
var out []*network.Cookie res, err := chromedp.Call(ctx, network.GetCookies, network.GetCookiesParams{})
err := chromedp.Run(ctx, chromedp.ActionFunc(func(ctx context.Context) error { if err != nil {
target := chromedp.FromContext(ctx).Target return nil, err
var err error }
out, err = network.GetCookies().Do(cdp.WithExecutor(ctx, target)) return res.Cookies, nil
return err
}))
return out, err
} }
// captureLocalStorage serialises the current page's localStorage to a // captureLocalStorage serialises the current page's localStorage to a
@@ -200,8 +195,8 @@ func captureLocalStorage(ctx context.Context, origin string) (json.RawMessage, e
return nil, nil return nil, nil
} }
const script = `JSON.stringify(Object.fromEntries(Object.keys(localStorage).map(function(k){return [k, localStorage.getItem(k)];})))` const script = `JSON.stringify(Object.fromEntries(Object.keys(localStorage).map(function(k){return [k, localStorage.getItem(k)];})))`
var lsJSON string lsJSON, err := chromedp.Run(ctx, chromedp.Evaluate[string](script))
if err := chromedp.Run(ctx, chromedp.Evaluate(script, &lsJSON)); err != nil { if err != nil {
return nil, err return nil, err
} }
if lsJSON == "" || lsJSON == "[]" || lsJSON == "{}" { if lsJSON == "" || lsJSON == "[]" || lsJSON == "{}" {
@@ -257,9 +252,8 @@ type onDiskCookie struct {
} }
// onDiskToCookieParam converts our on-disk shape into a CDP // onDiskToCookieParam converts our on-disk shape into a CDP
// network.CookieParam. Session cookies (Expires <= 0) get a nil Expires // network.CookieParam. Session cookies (Expires <= 0) keep a zero Expires;
// pointer; persistent cookies get a *cdp.TimeSinceEpoch built from the // persistent cookies get a cdp.TimeSinceEpoch built from the Unix timestamp.
// Unix timestamp.
func onDiskToCookieParam(c onDiskCookie) *network.CookieParam { func onDiskToCookieParam(c onDiskCookie) *network.CookieParam {
p := &network.CookieParam{ p := &network.CookieParam{
Name: c.Name, Name: c.Name,
@@ -271,8 +265,7 @@ func onDiskToCookieParam(c onDiskCookie) *network.CookieParam {
SameSite: parseSameSite(c.SameSite), SameSite: parseSameSite(c.SameSite),
} }
if c.Expires > 0 { if c.Expires > 0 {
t := cdp.TimeSinceEpoch(time.Unix(int64(c.Expires), 0)) p.Expires = cdp.TimeSinceEpoch(float64(int64(c.Expires)))
p.Expires = &t
} }
return p return p
} }
+6 -7
View File
@@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/chromedp" "github.com/chromedp/chromedp"
) )
@@ -13,8 +12,8 @@ import (
// a separate chromedp.Run so a slow extraction does not re-do navigation. // a separate chromedp.Run so a slow extraction does not re-do navigation.
func (r *Reader) extractHTML(ctx context.Context, selector string) (string, error) { func (r *Reader) extractHTML(ctx context.Context, selector string) (string, error) {
if selector == "" { if selector == "" {
var html string html, err := chromedp.Run(ctx, chromedp.OuterHTML(chromedp.CSS("html")))
if err := chromedp.Run(ctx, chromedp.OuterHTML("html", &html, chromedp.ByQuery)); err != nil { if err != nil {
return "", fmt.Errorf("read document: %w", err) return "", fmt.Errorf("read document: %w", err)
} }
return html, nil return html, nil
@@ -22,16 +21,16 @@ func (r *Reader) extractHTML(ctx context.Context, selector string) (string, erro
// Verify the selector matches at least one node; an empty result is // Verify the selector matches at least one node; an empty result is
// almost always a caller mistake, not an empty page. // almost always a caller mistake, not an empty page.
var nodes []*cdp.Node nodes, err := chromedp.Run(ctx, chromedp.Nodes(chromedp.CSS(selector)))
if err := chromedp.Run(ctx, chromedp.Nodes(selector, &nodes, chromedp.ByQuery)); err != nil { if err != nil {
return "", fmt.Errorf("locate %q: %w", selector, err) return "", fmt.Errorf("locate %q: %w", selector, err)
} }
if len(nodes) == 0 { if len(nodes) == 0 {
return "", fmt.Errorf("selector %q matched no elements", selector) return "", fmt.Errorf("selector %q matched no elements", selector)
} }
var html string html, err := chromedp.Run(ctx, chromedp.OuterHTML(chromedp.CSS(selector)))
if err := chromedp.Run(ctx, chromedp.OuterHTML(selector, &html, chromedp.ByQuery)); err != nil { if err != nil {
return "", fmt.Errorf("extract %q: %w", selector, err) return "", fmt.Errorf("extract %q: %w", selector, err)
} }
return html, nil return html, nil
+11 -8
View File
@@ -94,12 +94,12 @@ func (r *Reader) Read(parentCtx context.Context, opts ReadOptions) (*ReadResult,
// Build the action chain. Cookies were already applied by NewContext // Build the action chain. Cookies were already applied by NewContext
// (if a session exists). localStorage is applied post-navigation // (if a session exists). localStorage is applied post-navigation
// because it is origin-scoped. // because it is origin-scoped.
actions := []chromedp.Action{ actions := []chromedp.Action[chromedp.Void]{
chromedp.Navigate(opts.URL), chromedp.Navigate(opts.URL),
chromedp.WaitReady("body"), chromedp.WaitReady("body"),
} }
if statePath != "" { if statePath != "" {
actions = append(actions, chromedp.ActionFunc(func(ctx context.Context) error { actions = append(actions, chromedp.Func(func(ctx context.Context, _ *chromedp.Target) error {
return browser.ApplyLocalStorageOnCurrentOrigin(ctx, statePath) return browser.ApplyLocalStorageOnCurrentOrigin(ctx, statePath)
})) }))
} }
@@ -109,14 +109,17 @@ func (r *Reader) Read(parentCtx context.Context, opts ReadOptions) (*ReadResult,
chromedp.Sleep(500*time.Millisecond), chromedp.Sleep(500*time.Millisecond),
) )
if opts.WaitSelector != "" { if opts.WaitSelector != "" {
actions = append(actions, chromedp.WaitVisible(opts.WaitSelector, chromedp.ByQuery)) actions = append(actions, chromedp.WaitVisible(chromedp.CSS(opts.WaitSelector)))
} }
actions = append(actions, actions = append(actions, chromedp.Func(func(ctx context.Context, t *chromedp.Target) (err error) {
chromedp.Title(&title), if title, err = chromedp.Title()(ctx, t); err != nil {
chromedp.Location(&finalURL), return err
) }
finalURL, err = chromedp.Location()(ctx, t)
return err
}))
if err := chromedp.Run(cdpCtx, actions...); err != nil { if err := chromedp.Do(cdpCtx, actions...); err != nil {
return nil, fmt.Errorf("navigate: %w", err) return nil, fmt.Errorf("navigate: %w", err)
} }
+10 -14
View File
@@ -8,7 +8,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/chromedp" "github.com/chromedp/chromedp"
"github.com/lukaszraczylo/mcp-readitall/internal/browser" "github.com/lukaszraczylo/mcp-readitall/internal/browser"
"github.com/modelcontextprotocol/go-sdk/mcp" "github.com/modelcontextprotocol/go-sdk/mcp"
@@ -78,11 +77,9 @@ func RegisterLogin(s *mcp.Server, pw *browser.Browser, sess *browser.SessionStor
return nil, LoginOutput{}, fmt.Errorf("clear cookies: %w", err) return nil, LoginOutput{}, fmt.Errorf("clear cookies: %w", err)
} }
var title string if err := chromedp.Do(browserCtx,
if err := chromedp.Run(browserCtx,
chromedp.Navigate(in.URL), chromedp.Navigate(in.URL),
chromedp.WaitReady("body"), chromedp.WaitReady("body"),
chromedp.Title(&title),
); err != nil { ); err != nil {
return nil, LoginOutput{}, fmt.Errorf("navigate: %w", err) return nil, LoginOutput{}, fmt.Errorf("navigate: %w", err)
} }
@@ -146,8 +143,8 @@ func waitForLogin(ctx context.Context, pageCtx context.Context, in LoginInput, t
check := func() (bool, error) { check := func() (bool, error) {
if in.SuccessURL != "" { if in.SuccessURL != "" {
var current string current, err := chromedp.Run(pageCtx, chromedp.Location())
if err := chromedp.Run(pageCtx, chromedp.Location(&current)); err != nil { if err != nil {
return false, err return false, err
} }
if strings.Contains(current, in.SuccessURL) { if strings.Contains(current, in.SuccessURL) {
@@ -155,16 +152,15 @@ func waitForLogin(ctx context.Context, pageCtx context.Context, in LoginInput, t
} }
} }
if in.SuccessSelector != "" { if in.SuccessSelector != "" {
var nodes []*cdp.Node nodes, err := chromedp.Run(pageCtx, chromedp.Nodes(chromedp.CSS(in.SuccessSelector)))
if err := chromedp.Run(pageCtx, chromedp.Nodes(in.SuccessSelector, &nodes, chromedp.ByQuery)); err != nil { if err != nil {
return false, err return false, err
} }
if len(nodes) > 0 { if len(nodes) > 0 {
var visible bool visible, err := chromedp.Run(pageCtx, chromedp.Evaluate[bool](
if err := chromedp.Run(pageCtx, chromedp.Evaluate(
`(()=>{const e=document.querySelector(`+jsQuote(in.SuccessSelector)+`);return !!e && e.getBoundingClientRect().height>0;})()`, `(()=>{const e=document.querySelector(`+jsQuote(in.SuccessSelector)+`);return !!e && e.getBoundingClientRect().height>0;})()`,
&visible, ))
)); err != nil { if err != nil {
return false, err return false, err
} }
if visible { if visible {
@@ -205,8 +201,8 @@ func waitForLogin(ctx context.Context, pageCtx context.Context, in LoginInput, t
// currentLocation returns the page's current URL or "" if the query // currentLocation returns the page's current URL or "" if the query
// fails (e.g. the browser has already been torn down). // fails (e.g. the browser has already been torn down).
func currentLocation(ctx context.Context) string { func currentLocation(ctx context.Context) string {
var s string s, err := chromedp.Run(ctx, chromedp.Location())
if err := chromedp.Run(ctx, chromedp.Location(&s)); err != nil { if err != nil {
return "" return ""
} }
return s return s
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"packageRules": [
{
"description": "chromedp pins an exact cdproto; bump them together",
"matchManagers": ["gomod"],
"matchPackageNames": ["github.com/chromedp/chromedp", "github.com/chromedp/cdproto"],
"groupName": "chromedp"
}
]
}