diff --git a/go/display/http/doc.go b/go/display/http/doc.go
new file mode 100644
index 0000000..5a175e8
--- /dev/null
+++ b/go/display/http/doc.go
@@ -0,0 +1,7 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+// Package httpdisplay serves server-rendered TypeScript output and static
+// assets over HTTP.
+package httpdisplay
diff --git a/go/display/http/http.go b/go/display/http/http.go
new file mode 100644
index 0000000..bef65b9
--- /dev/null
+++ b/go/display/http/http.go
@@ -0,0 +1,93 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package httpdisplay
+
+import (
+ nethttp "net/http"
+
+ core "dappco.re/go"
+ tsengine "dappco.re/go/html/engine/ts"
+)
+
+// Option configures Handler.
+type Option func(*handlerOptions)
+
+type handlerOptions struct {
+ entry string
+}
+
+// WithEntry selects the TypeScript or JavaScript SSR entry module.
+func WithEntry(entry string) Option {
+ return func(options *handlerOptions) {
+ options.entry = entry
+ }
+}
+
+// Handler returns an HTTP handler that serves files found under assetsDir and
+// server-renders every other request through engine.
+//
+// Static files retain their standard content types and caching semantics.
+// Rendered responses receive text/html; charset=utf-8.
+func Handler(engine tsengine.Renderer, assetsDir string, opts ...Option) nethttp.Handler {
+ options := handlerOptions{}
+ for _, option := range opts {
+ if option != nil {
+ option(&options)
+ }
+ }
+
+ var assets nethttp.Handler
+ if assetsDir != "" {
+ assets = nethttp.FileServer(nethttp.Dir(assetsDir))
+ }
+
+ return nethttp.HandlerFunc(func(writer nethttp.ResponseWriter, request *nethttp.Request) {
+ if assets != nil && isAssetRequest(assetsDir, request) {
+ assets.ServeHTTP(writer, request)
+ return
+ }
+ if engine == nil {
+ nethttp.Error(writer, "render engine unavailable", nethttp.StatusInternalServerError)
+ return
+ }
+ if core.Trim(options.entry) == "" {
+ nethttp.Error(writer, "render entry unavailable", nethttp.StatusInternalServerError)
+ return
+ }
+
+ input := map[string]any{
+ "method": request.Method,
+ "url": request.URL.String(),
+ "path": request.URL.Path,
+ "query": request.URL.Query(),
+ "headers": request.Header.Clone(),
+ "host": request.Host,
+ }
+ output, err := engine.Render(request.Context(), options.entry, input)
+ if err != nil {
+ nethttp.Error(writer, "render failed", nethttp.StatusInternalServerError)
+ return
+ }
+
+ writer.Header().Set("Content-Type", "text/html; charset=utf-8")
+ writer.WriteHeader(nethttp.StatusOK)
+ _, _ = writer.Write(output)
+ })
+}
+
+func isAssetRequest(assetsDir string, request *nethttp.Request) bool {
+ if request.Method != nethttp.MethodGet && request.Method != nethttp.MethodHead {
+ return false
+ }
+
+ file, err := nethttp.Dir(assetsDir).Open(request.URL.Path)
+ if err != nil {
+ return false
+ }
+ defer file.Close()
+
+ info, err := file.Stat()
+ return err == nil && !info.IsDir()
+}
diff --git a/go/display/http/http_example_test.go b/go/display/http/http_example_test.go
new file mode 100644
index 0000000..bae2c70
--- /dev/null
+++ b/go/display/http/http_example_test.go
@@ -0,0 +1,13 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package httpdisplay
+
+func ExampleHandler() {
+ _ = Handler
+}
+
+func ExampleWithEntry() {
+ _ = WithEntry("server.ts")
+}
diff --git a/go/display/http/http_test.go b/go/display/http/http_test.go
new file mode 100644
index 0000000..ed91276
--- /dev/null
+++ b/go/display/http/http_test.go
@@ -0,0 +1,112 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package httpdisplay
+
+import (
+ nethttp "net/http"
+ "net/http/httptest"
+ "testing"
+
+ core "dappco.re/go"
+)
+
+type renderStub struct {
+ output []byte
+ err error
+ calls int
+ entry string
+ input any
+}
+
+func (s *renderStub) Render(_ core.Context, entry string, input any) ([]byte, error) {
+ s.calls++
+ s.entry = entry
+ s.input = input
+ return s.output, s.err
+}
+
+func TestHttp_Handler_Good(t *testing.T) {
+ renderer := &renderStub{output: []byte("rendered")}
+ handler := Handler(renderer, "", WithEntry("server.ts"))
+ recorder := httptest.NewRecorder()
+ request := httptest.NewRequest(nethttp.MethodGet, "http://example.test/dashboard?tab=one", nil)
+
+ handler.ServeHTTP(recorder, request)
+
+ core.AssertEqual(t, nethttp.StatusOK, recorder.Code)
+ core.AssertEqual(t, "rendered", recorder.Body.String())
+ core.AssertEqual(t, "text/html; charset=utf-8", recorder.Header().Get("Content-Type"))
+ core.AssertEqual(t, 1, renderer.calls)
+ requestInput := renderer.input.(map[string]any)
+ core.AssertEqual(t, "/dashboard", requestInput["path"])
+}
+
+func TestHttp_Handler_Bad(t *testing.T) {
+ renderer := &renderStub{err: core.E("test.render", "failed", nil)}
+ handler := Handler(renderer, "", WithEntry("broken.ts"))
+ recorder := httptest.NewRecorder()
+ request := httptest.NewRequest(nethttp.MethodGet, "http://example.test/", nil)
+
+ handler.ServeHTTP(recorder, request)
+
+ core.AssertEqual(t, nethttp.StatusInternalServerError, recorder.Code)
+ core.AssertContains(t, recorder.Body.String(), "render failed")
+ core.AssertEqual(t, 1, renderer.calls)
+}
+
+func TestHttp_Handler_Ugly(t *testing.T) {
+ assetsDir := t.TempDir()
+ writeResult := core.WriteFile(core.PathJoin(assetsDir, "app.js"), []byte("asset();"), 0o600)
+ core.RequireTrue(t, writeResult.OK, writeResult.Error())
+ renderer := &renderStub{output: []byte("unused")}
+ handler := Handler(renderer, assetsDir, WithEntry("server.ts"))
+ recorder := httptest.NewRecorder()
+ request := httptest.NewRequest(nethttp.MethodGet, "http://example.test/app.js", nil)
+
+ handler.ServeHTTP(recorder, request)
+
+ core.AssertEqual(t, nethttp.StatusOK, recorder.Code)
+ core.AssertEqual(t, "asset();", recorder.Body.String())
+ core.AssertEqual(t, 0, renderer.calls)
+}
+
+func TestHttp_WithEntry_Good(t *testing.T) {
+ renderer := &renderStub{output: []byte("ok")}
+ handler := Handler(renderer, "", WithEntry("main.server.ts"))
+ recorder := httptest.NewRecorder()
+ request := httptest.NewRequest(nethttp.MethodGet, "http://example.test/", nil)
+
+ handler.ServeHTTP(recorder, request)
+
+ core.AssertEqual(t, nethttp.StatusOK, recorder.Code)
+ core.AssertEqual(t, "main.server.ts", renderer.entry)
+ core.AssertEqual(t, 1, renderer.calls)
+}
+
+func TestHttp_WithEntry_Bad(t *testing.T) {
+ renderer := &renderStub{output: []byte("unused")}
+ handler := Handler(renderer, "", WithEntry(" "))
+ recorder := httptest.NewRecorder()
+ request := httptest.NewRequest(nethttp.MethodGet, "http://example.test/", nil)
+
+ handler.ServeHTTP(recorder, request)
+
+ core.AssertEqual(t, nethttp.StatusInternalServerError, recorder.Code)
+ core.AssertContains(t, recorder.Body.String(), "entry unavailable")
+ core.AssertEqual(t, 0, renderer.calls)
+}
+
+func TestHttp_WithEntry_Ugly(t *testing.T) {
+ renderer := &renderStub{output: []byte("last wins")}
+ handler := Handler(renderer, "", WithEntry("first.ts"), WithEntry("second.ts"))
+ recorder := httptest.NewRecorder()
+ request := httptest.NewRequest(nethttp.MethodGet, "http://example.test/", nil)
+
+ handler.ServeHTTP(recorder, request)
+
+ core.AssertEqual(t, nethttp.StatusOK, recorder.Code)
+ core.AssertEqual(t, "second.ts", renderer.entry)
+ core.AssertEqual(t, "last wins", recorder.Body.String())
+}
diff --git a/go/display/pipe/doc.go b/go/display/pipe/doc.go
new file mode 100644
index 0000000..0fd4b1a
--- /dev/null
+++ b/go/display/pipe/doc.go
@@ -0,0 +1,6 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+// Package pipe emits one server-rendered TypeScript result to a writer.
+package pipe
diff --git a/go/display/pipe/pipe.go b/go/display/pipe/pipe.go
new file mode 100644
index 0000000..f3d88ba
--- /dev/null
+++ b/go/display/pipe/pipe.go
@@ -0,0 +1,34 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package pipe
+
+import (
+ core "dappco.re/go"
+ tsengine "dappco.re/go/html/engine/ts"
+)
+
+// Emit renders entry once with a nil input and writes the exact output bytes
+// to writer.
+func Emit(engine tsengine.Renderer, entry string, writer core.Writer) error {
+ if engine == nil {
+ return core.E("pipe.Emit", "render engine is nil", nil)
+ }
+ if writer == nil {
+ return core.E("pipe.Emit", "writer is nil", nil)
+ }
+
+ output, err := engine.Render(core.Background(), entry, nil)
+ if err != nil {
+ return core.E("pipe.Emit", "render TypeScript entry", err)
+ }
+ written, err := writer.Write(output)
+ if err != nil {
+ return core.E("pipe.Emit", "write rendered output", err)
+ }
+ if written != len(output) {
+ return core.E("pipe.Emit", "short write", nil)
+ }
+ return nil
+}
diff --git a/go/display/pipe/pipe_example_test.go b/go/display/pipe/pipe_example_test.go
new file mode 100644
index 0000000..4e7a442
--- /dev/null
+++ b/go/display/pipe/pipe_example_test.go
@@ -0,0 +1,9 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package pipe
+
+func ExampleEmit() {
+ _ = Emit
+}
diff --git a/go/display/pipe/pipe_test.go b/go/display/pipe/pipe_test.go
new file mode 100644
index 0000000..bb2ce5c
--- /dev/null
+++ b/go/display/pipe/pipe_test.go
@@ -0,0 +1,65 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package pipe
+
+import (
+ "testing"
+
+ core "dappco.re/go"
+)
+
+type pipeRenderer struct {
+ output []byte
+ err error
+ entry string
+ input any
+}
+
+func (r *pipeRenderer) Render(_ core.Context, entry string, input any) ([]byte, error) {
+ r.entry = entry
+ r.input = input
+ return r.output, r.err
+}
+
+type shortWriter struct{}
+
+func (shortWriter) Write(data []byte) (int, error) {
+ if len(data) == 0 {
+ return 0, nil
+ }
+ return len(data) - 1, nil
+}
+
+func TestPipe_Emit_Good(t *testing.T) {
+ renderer := &pipeRenderer{output: []byte("
ready
")}
+ output := core.NewBuffer()
+ err := Emit(renderer, "server.ts", output)
+
+ core.AssertNoError(t, err)
+ core.AssertEqual(t, "ready
", output.String())
+ core.AssertEqual(t, "server.ts", renderer.entry)
+ core.AssertNil(t, renderer.input)
+}
+
+func TestPipe_Emit_Bad(t *testing.T) {
+ renderer := &pipeRenderer{err: core.E("test.render", "failed", nil)}
+ output := core.NewBuffer()
+ err := Emit(renderer, "broken.ts", output)
+
+ core.AssertError(t, err)
+ core.AssertContains(t, err.Error(), "render TypeScript entry")
+ core.AssertEqual(t, 0, output.Len())
+ core.AssertEqual(t, "broken.ts", renderer.entry)
+}
+
+func TestPipe_Emit_Ugly(t *testing.T) {
+ renderer := &pipeRenderer{output: []byte("partial")}
+ err := Emit(renderer, "server.ts", shortWriter{})
+
+ core.AssertError(t, err)
+ core.AssertContains(t, err.Error(), "short write")
+ core.AssertEqual(t, "server.ts", renderer.entry)
+ core.AssertNil(t, renderer.input)
+}
diff --git a/go/display/socket/doc.go b/go/display/socket/doc.go
new file mode 100644
index 0000000..0ae8d51
--- /dev/null
+++ b/go/display/socket/doc.go
@@ -0,0 +1,6 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+// Package socket serves TypeScript SSR over an existing TCP or Unix listener.
+package socket
diff --git a/go/display/socket/socket.go b/go/display/socket/socket.go
new file mode 100644
index 0000000..cf81bf7
--- /dev/null
+++ b/go/display/socket/socket.go
@@ -0,0 +1,31 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package socket
+
+import (
+ "net"
+ nethttp "net/http"
+
+ core "dappco.re/go"
+ httpdisplay "dappco.re/go/html/display/http"
+ tsengine "dappco.re/go/html/engine/ts"
+)
+
+// Serve serves the HTTP SSR handler over listener until the listener closes.
+// The listener may use TCP or a Unix-domain socket.
+func Serve(engine tsengine.Renderer, listener net.Listener, opts ...httpdisplay.Option) error {
+ if engine == nil {
+ return core.E("socket.Serve", "render engine is nil", nil)
+ }
+ if listener == nil {
+ return core.E("socket.Serve", "listener is nil", nil)
+ }
+
+ err := nethttp.Serve(listener, httpdisplay.Handler(engine, "", opts...))
+ if err == nil || core.Is(err, nethttp.ErrServerClosed) || core.Is(err, net.ErrClosed) {
+ return nil
+ }
+ return core.E("socket.Serve", "serve render listener", err)
+}
diff --git a/go/display/socket/socket_example_test.go b/go/display/socket/socket_example_test.go
new file mode 100644
index 0000000..6c5fb5d
--- /dev/null
+++ b/go/display/socket/socket_example_test.go
@@ -0,0 +1,9 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package socket
+
+func ExampleServe() {
+ _ = Serve
+}
diff --git a/go/display/socket/socket_test.go b/go/display/socket/socket_test.go
new file mode 100644
index 0000000..a892959
--- /dev/null
+++ b/go/display/socket/socket_test.go
@@ -0,0 +1,68 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package socket
+
+import (
+ nethttp "net/http"
+ "testing"
+
+ core "dappco.re/go"
+ httpdisplay "dappco.re/go/html/display/http"
+)
+
+type socketRenderer struct {
+ output []byte
+ entry string
+}
+
+func (r *socketRenderer) Render(_ core.Context, entry string, _ any) ([]byte, error) {
+ r.entry = entry
+ return r.output, nil
+}
+
+func TestSocket_Serve_Good(t *testing.T) {
+ listenResult := core.NetListen("tcp", "127.0.0.1:0")
+ core.RequireTrue(t, listenResult.OK, listenResult.Error())
+ listener := listenResult.Value.(core.Listener)
+ renderer := &socketRenderer{output: []byte("socket")}
+ done := make(chan error, 1)
+ go func() {
+ done <- Serve(renderer, listener, httpdisplay.WithEntry("server.ts"))
+ }()
+
+ client := &nethttp.Client{Timeout: 2 * core.Second}
+ response, err := client.Get("http://" + listener.Addr().String() + "/")
+ core.RequireNoError(t, err)
+ readResult := core.ReadAll(response.Body)
+ core.RequireTrue(t, readResult.OK, readResult.Error())
+ core.AssertEqual(t, "socket", readResult.Value.(string))
+ core.AssertEqual(t, "server.ts", renderer.entry)
+
+ core.AssertNoError(t, listener.Close())
+ core.AssertNoError(t, <-done)
+}
+
+func TestSocket_Serve_Bad(t *testing.T) {
+ listenResult := core.NetListen("tcp", "127.0.0.1:0")
+ core.RequireTrue(t, listenResult.OK, listenResult.Error())
+ listener := listenResult.Value.(core.Listener)
+ defer listener.Close()
+
+ err := Serve(nil, listener)
+
+ core.AssertError(t, err)
+ core.AssertContains(t, err.Error(), "engine is nil")
+ core.AssertContains(t, err.Error(), "socket.Serve")
+}
+
+func TestSocket_Serve_Ugly(t *testing.T) {
+ renderer := &socketRenderer{output: []byte("unused")}
+ err := Serve(renderer, nil, httpdisplay.WithEntry("server.ts"))
+
+ core.AssertError(t, err)
+ core.AssertContains(t, err.Error(), "listener is nil")
+ core.AssertEqual(t, "", renderer.entry)
+ core.AssertEqual(t, "unused", core.AsString(renderer.output))
+}
diff --git a/go/engine/ts/doc.go b/go/engine/ts/doc.go
new file mode 100644
index 0000000..e46528c
--- /dev/null
+++ b/go/engine/ts/doc.go
@@ -0,0 +1,7 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+// Package ts renders TypeScript and JavaScript modules in a CoreTS Deno
+// sidecar. It is server-only and is deliberately excluded from js/wasm builds.
+package ts
diff --git a/go/engine/ts/engine.go b/go/engine/ts/engine.go
new file mode 100644
index 0000000..f0cbf31
--- /dev/null
+++ b/go/engine/ts/engine.go
@@ -0,0 +1,352 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package ts
+
+import (
+ core "dappco.re/go"
+ corets "dappco.re/go/ts"
+)
+
+const (
+ renderModulePrefix = "go-render-"
+ renderGroupPrefix = "go-render-ts-"
+)
+
+// Renderer is the content-producing contract shared by the server-side
+// display packages.
+type Renderer interface {
+ Render(ctx core.Context, entry string, input any) ([]byte, error)
+}
+
+// Engine owns a CoreTS service and its managed Deno sidecar.
+type Engine struct {
+ mu core.RWMutex
+ app *core.Core
+ service *corets.Service
+ tempDir string
+ appRoot string
+ closed bool
+}
+
+// New starts a CoreTS service and its configured Deno sidecar.
+//
+// SidecarArgs must launch a CoreTS-compatible Deno runtime. A typical runtime
+// uses: run, -A, --unstable-worker-options, and CoreTS's runtime/main.ts.
+func New(opts corets.Options) (*Engine, error) {
+ if len(opts.SidecarArgs) == 0 {
+ return nil, core.E("ts.New", "CoreTS SidecarArgs are required", nil)
+ }
+
+ tempResult := core.MkdirTemp("", renderGroupPrefix)
+ if !tempResult.OK {
+ return nil, core.E("ts.New", "create render workspace", resultError(tempResult))
+ }
+ tempDir := tempResult.Value.(string)
+
+ if opts.SocketPath == "" {
+ opts.SocketPath = core.PathJoin(tempDir, "core.sock")
+ }
+ if opts.DenoSocketPath == "" {
+ opts.DenoSocketPath = core.PathJoin(tempDir, "deno.sock")
+ }
+
+ app := core.New(core.WithService(corets.NewServiceFactory(opts)))
+ service, ok := core.ServiceFor[*corets.Service](app, "ts")
+ if !ok || service == nil {
+ removeResult := core.RemoveAll(tempDir)
+ if !removeResult.OK {
+ return nil, core.E("ts.New", "remove render workspace after CoreTS registration failure", resultError(removeResult))
+ }
+ return nil, core.E("ts.New", "register CoreTS service", nil)
+ }
+
+ startResult := app.ServiceStartup(core.Background(), nil)
+ if !startResult.OK {
+ shutdownResult := app.ServiceShutdown(core.Background())
+ if !shutdownResult.OK {
+ return nil, core.E("ts.New", "clean up after CoreTS startup failure", resultError(shutdownResult))
+ }
+ removeResult := core.RemoveAll(tempDir)
+ if !removeResult.OK {
+ return nil, core.E("ts.New", "remove render workspace after CoreTS startup failure", resultError(removeResult))
+ }
+ return nil, core.E("ts.New", "start CoreTS service", resultError(startResult))
+ }
+ if service.DenoClient() == nil {
+ shutdownResult := app.ServiceShutdown(core.Background())
+ if !shutdownResult.OK {
+ return nil, core.E("ts.New", "stop CoreTS service without a Deno client", resultError(shutdownResult))
+ }
+ removeResult := core.RemoveAll(tempDir)
+ if !removeResult.OK {
+ return nil, core.E("ts.New", "remove render workspace without a Deno client", resultError(removeResult))
+ }
+ return nil, core.E("ts.New", "CoreTS Deno client is not connected", nil)
+ }
+
+ return &Engine{
+ app: app,
+ service: service,
+ tempDir: tempDir,
+ appRoot: canonicalPath(opts.AppRoot),
+ }, nil
+}
+
+// Render loads a permission-scoped wrapper module in CoreTS, invokes the
+// entry's render export with input, and returns its HTML or byte output.
+//
+// The entry may be a local .ts/.tsx/.js module or a data: module. It must
+// export render(input), a default function, or a default object with a render
+// method. String, []byte/Uint8Array, ArrayBuffer, Blob, Response, and
+// JSON-serialisable results are supported.
+func (e *Engine) Render(ctx core.Context, entry string, input any) ([]byte, error) {
+ if e == nil {
+ return nil, core.E("ts.Engine.Render", "engine is nil", nil)
+ }
+ if ctx == nil {
+ return nil, core.E("ts.Engine.Render", "context is nil", nil)
+ }
+ if err := ctx.Err(); err != nil {
+ return nil, core.E("ts.Engine.Render", "render context is done", err)
+ }
+
+ e.mu.RLock()
+ defer e.mu.RUnlock()
+
+ if e.closed || e.service == nil {
+ return nil, core.E("ts.Engine.Render", "engine is closed", nil)
+ }
+
+ entryPoint, entryReads, err := e.entryPoint(entry)
+ if err != nil {
+ return nil, err
+ }
+ inputJSON, err := marshalJSON("ts.Engine.Render", "serialise render input", input)
+ if err != nil {
+ return nil, err
+ }
+
+ randomResult := core.RandomString(16)
+ if !randomResult.OK {
+ return nil, core.E("ts.Engine.Render", "create module identity", resultError(randomResult))
+ }
+ identity := renderModulePrefix + randomResult.Value.(string)
+ workspaceResult := core.MkdirTemp(e.tempDir, identity+"-")
+ if !workspaceResult.OK {
+ return nil, core.E("ts.Engine.Render", "create isolated render workspace", resultError(workspaceResult))
+ }
+ renderDir := workspaceResult.Value.(string)
+ defer func() {
+ if removeResult := core.RemoveAll(renderDir); !removeResult.OK {
+ core.Warn("TypeScript render workspace cleanup failed", "path", renderDir, "err", resultError(removeResult))
+ }
+ }()
+ wrapperPath := core.PathJoin(renderDir, "render.ts")
+ outputPath := core.PathJoin(renderDir, "render.out")
+
+ wrapper, err := renderWrapper(entryPoint, inputJSON, outputPath)
+ if err != nil {
+ return nil, err
+ }
+ writeResult := core.WriteFile(wrapperPath, core.AsBytes(wrapper), 0o600)
+ if !writeResult.OK {
+ return nil, core.E("ts.Engine.Render", "write render wrapper", resultError(writeResult))
+ }
+
+ wrapperEntry := fileURL(wrapperPath)
+ permissions := corets.ModulePermissions{
+ Read: append([]string{renderDir}, entryReads...),
+ Write: []string{renderDir},
+ }
+ loadResponse, err := e.service.LoadModule(identity, wrapperEntry, permissions)
+ if err != nil {
+ return nil, core.E("ts.Engine.Render", "load TypeScript render module", err)
+ }
+ defer func() {
+ unloadResponse, unloadErr := e.service.UnloadModule(identity)
+ if unloadErr != nil {
+ core.Warn("TypeScript render module unload failed", "module", identity, "err", unloadErr)
+ return
+ }
+ if unloadResponse == nil || !unloadResponse.Ok {
+ core.Warn("TypeScript render module did not unload", "module", identity)
+ }
+ }()
+ if loadResponse == nil || !loadResponse.Ok {
+ message := "TypeScript render module was rejected"
+ if loadResponse != nil && loadResponse.Error != "" {
+ message = loadResponse.Error
+ }
+ return nil, core.E("ts.Engine.Render", message, nil)
+ }
+ if err := ctx.Err(); err != nil {
+ return nil, core.E("ts.Engine.Render", "render context is done", err)
+ }
+
+ readResult := core.ReadFile(outputPath)
+ if !readResult.OK {
+ return nil, core.E("ts.Engine.Render", "read rendered output", resultError(readResult))
+ }
+ return readResult.Value.([]byte), nil
+}
+
+// Close stops the CoreTS service and sidecar and removes the render workspace.
+// It is safe to call Close more than once.
+func (e *Engine) Close() error {
+ if e == nil {
+ return core.E("ts.Engine.Close", "engine is nil", nil)
+ }
+
+ e.mu.Lock()
+ defer e.mu.Unlock()
+
+ if e.closed {
+ return nil
+ }
+ e.closed = true
+
+ var closeErr error
+ if e.app != nil {
+ shutdownResult := e.app.ServiceShutdown(core.Background())
+ if !shutdownResult.OK {
+ closeErr = core.E("ts.Engine.Close", "stop CoreTS service", resultError(shutdownResult))
+ }
+ }
+ if e.tempDir != "" {
+ removeResult := core.RemoveAll(e.tempDir)
+ if !removeResult.OK && closeErr == nil {
+ closeErr = core.E("ts.Engine.Close", "remove render workspace", resultError(removeResult))
+ }
+ }
+
+ e.app = nil
+ e.service = nil
+ e.tempDir = ""
+ return closeErr
+}
+
+func (e *Engine) entryPoint(entry string) (string, []string, error) {
+ entry = core.Trim(entry)
+ if entry == "" {
+ return "", nil, core.E("ts.Engine.Render", "entry is required", nil)
+ }
+ if core.HasPrefix(entry, "data:") {
+ return entry, nil, nil
+ }
+
+ path := entry
+ if core.HasPrefix(entry, "file:") {
+ parseResult := core.URLParse(entry)
+ if !parseResult.OK {
+ return "", nil, core.E("ts.Engine.Render", "parse file entry URL", resultError(parseResult))
+ }
+ parsed := parseResult.Value.(*core.URL)
+ if parsed.Scheme != "file" || (parsed.Host != "" && parsed.Host != "localhost") {
+ return "", nil, core.E("ts.Engine.Render", "entry must be a local file URL", nil)
+ }
+ path = parsed.Path
+ } else if !core.PathIsAbs(entry) {
+ parseResult := core.URLParse(entry)
+ if parseResult.OK && parseResult.Value.(*core.URL).Scheme != "" {
+ return "", nil, core.E("ts.Engine.Render", "remote module entries are not permitted", nil)
+ }
+ }
+
+ absoluteResult := core.PathAbs(path)
+ if !absoluteResult.OK {
+ return "", nil, core.E("ts.Engine.Render", "resolve module entry", resultError(absoluteResult))
+ }
+ absolute := absoluteResult.Value.(string)
+ resolvedResult := core.PathEvalSymlinks(absolute)
+ if !resolvedResult.OK {
+ return "", nil, core.E("ts.Engine.Render", "resolve module entry symlinks", resultError(resolvedResult))
+ }
+ resolved := resolvedResult.Value.(string)
+
+ statResult := core.Stat(resolved)
+ if !statResult.OK {
+ return "", nil, core.E("ts.Engine.Render", "stat module entry", resultError(statResult))
+ }
+ if statResult.Value.(core.FsFileInfo).IsDir() {
+ return "", nil, core.E("ts.Engine.Render", "module entry is a directory", nil)
+ }
+
+ readRoot := core.PathDir(resolved)
+ if e.appRoot != "" {
+ if !corets.CheckPath(resolved, []string{e.appRoot}) {
+ return "", nil, core.E("ts.Engine.Render", "module entry is outside CoreTS AppRoot", nil)
+ }
+ readRoot = e.appRoot
+ }
+ return fileURL(resolved), []string{readRoot}, nil
+}
+
+func renderWrapper(entryPoint, inputJSON, outputPath string) (string, error) {
+ entryJSON, err := marshalJSON("ts.Engine.Render", "serialise module entry", entryPoint)
+ if err != nil {
+ return "", err
+ }
+ outputJSON, err := marshalJSON("ts.Engine.Render", "serialise output path", outputPath)
+ if err != nil {
+ return "", err
+ }
+
+ return core.Concat(
+ "// Generated by dappco.re/go/html/engine/ts.\n",
+ "export async function init() {\n",
+ " const module = await import(", entryJSON, ");\n",
+ " let render = module.render;\n",
+ " if (typeof render !== \"function\" && typeof module.default === \"function\") render = module.default;\n",
+ " if (typeof render !== \"function\" && module.default && typeof module.default.render === \"function\") render = module.default.render.bind(module.default);\n",
+ " if (typeof render !== \"function\") throw new Error(\"render entry must export render(input) or a default renderer\");\n",
+ " const value = await render(", inputJSON, ");\n",
+ " const encoder = new TextEncoder();\n",
+ " let output;\n",
+ " if (typeof value === \"string\") output = encoder.encode(value);\n",
+ " else if (value instanceof Uint8Array) output = value;\n",
+ " else if (value instanceof ArrayBuffer) output = new Uint8Array(value);\n",
+ " else if (typeof Blob !== \"undefined\" && value instanceof Blob) output = new Uint8Array(await value.arrayBuffer());\n",
+ " else if (typeof Response !== \"undefined\" && value instanceof Response) output = new Uint8Array(await value.arrayBuffer());\n",
+ " else if (value === undefined || value === null) output = new Uint8Array();\n",
+ " else output = encoder.encode(JSON.stringify(value));\n",
+ " await Deno.writeFile(", outputJSON, ", output, { create: true, createNew: true, write: true });\n",
+ "}\n",
+ ), nil
+}
+
+func marshalJSON(operation, message string, value any) (string, error) {
+ result := core.JSONMarshal(value)
+ if !result.OK {
+ return "", core.E(operation, message, resultError(result))
+ }
+ return core.AsString(result.Value.([]byte)), nil
+}
+
+func fileURL(path string) string {
+ return (&core.URL{Scheme: "file", Path: core.PathToSlash(path)}).String()
+}
+
+func canonicalPath(path string) string {
+ if path == "" {
+ return ""
+ }
+ absoluteResult := core.PathAbs(path)
+ if !absoluteResult.OK {
+ return path
+ }
+ absolute := absoluteResult.Value.(string)
+ resolvedResult := core.PathEvalSymlinks(absolute)
+ if resolvedResult.OK {
+ return resolvedResult.Value.(string)
+ }
+ return absolute
+}
+
+func resultError(result core.Result) error {
+ if err, ok := result.Value.(error); ok {
+ return err
+ }
+ return core.E("ts", result.Error(), nil)
+}
diff --git a/go/engine/ts/engine_example_test.go b/go/engine/ts/engine_example_test.go
new file mode 100644
index 0000000..a45377b
--- /dev/null
+++ b/go/engine/ts/engine_example_test.go
@@ -0,0 +1,17 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package ts
+
+func ExampleNew() {
+ _ = New
+}
+
+func ExampleEngine_Render() {
+ _ = (*Engine).Render
+}
+
+func ExampleEngine_Close() {
+ _ = (*Engine).Close
+}
diff --git a/go/engine/ts/engine_test.go b/go/engine/ts/engine_test.go
new file mode 100644
index 0000000..56eb47e
--- /dev/null
+++ b/go/engine/ts/engine_test.go
@@ -0,0 +1,256 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package ts
+
+import (
+ "testing"
+
+ core "dappco.re/go"
+ corets "dappco.re/go/ts"
+)
+
+func TestEngine_New_Good(t *testing.T) {
+ engine, err := New(smokeOptions(t))
+ core.RequireNoError(t, err)
+ core.AssertNotNil(t, engine)
+ core.AssertNotNil(t, engine.service)
+ core.AssertTrue(t, engine.service.Sidecar().IsRunning())
+ core.AssertNoError(t, engine.Close())
+}
+
+func TestEngine_New_Bad(t *testing.T) {
+ engine, err := New(corets.Options{})
+ core.AssertNil(t, engine)
+ core.AssertError(t, err)
+ core.AssertContains(t, err.Error(), "SidecarArgs")
+}
+
+func TestEngine_New_Ugly(t *testing.T) {
+ engine, err := New(corets.Options{
+ DenoPath: core.PathJoin(t.TempDir(), "missing-deno"),
+ SidecarArgs: []string{"run", "runtime.ts"},
+ })
+ core.AssertNil(t, engine)
+ core.AssertError(t, err)
+ core.AssertContains(t, err.Error(), "start CoreTS service")
+}
+
+func TestEngine_Render_Good(t *testing.T) {
+ engine := newSmokeEngine(t)
+ defer func() { core.AssertNoError(t, engine.Close()) }()
+
+ entry := inlineModule(`export function render(input: {name: string}) {
+ return "Hello, " + input.name + "";
+ }`)
+ output, err := engine.Render(core.Background(), entry, map[string]any{"name": "Deno"})
+ core.AssertNoError(t, err)
+ core.AssertEqual(t, "Hello, Deno", core.AsString(output))
+}
+
+func TestEngine_Render_Bad(t *testing.T) {
+ engine := &Engine{closed: true}
+ output, err := engine.Render(core.Background(), "entry.ts", nil)
+ core.AssertNil(t, output)
+ core.AssertError(t, err)
+ core.AssertContains(t, err.Error(), "closed")
+}
+
+func TestEngine_Render_Ugly(t *testing.T) {
+ engine := newSmokeEngine(t)
+ defer func() { core.AssertNoError(t, engine.Close()) }()
+
+ entry := inlineModule(`export default function() {
+ return new Uint8Array([0, 1, 2, 255]);
+ }`)
+ output, err := engine.Render(core.Background(), entry, nil)
+ core.AssertNoError(t, err)
+ core.AssertEqual(t, []byte{0, 1, 2, 255}, output)
+}
+
+func TestEngine_Close_Good(t *testing.T) {
+ engine := newSmokeEngine(t)
+ sidecar := engine.service.Sidecar()
+ core.AssertTrue(t, sidecar.IsRunning())
+ core.AssertNoError(t, engine.Close())
+ core.AssertFalse(t, sidecar.IsRunning())
+}
+
+func TestEngine_Close_Bad(t *testing.T) {
+ var engine *Engine
+ err := engine.Close()
+ core.AssertError(t, err)
+ core.AssertContains(t, err.Error(), "engine is nil")
+ core.AssertContains(t, err.Error(), "Engine.Close")
+}
+
+func TestEngine_Close_Ugly(t *testing.T) {
+ engine := newSmokeEngine(t)
+ core.AssertNoError(t, engine.Close())
+ core.AssertNoError(t, engine.Close())
+ core.AssertTrue(t, engine.closed)
+}
+
+func newSmokeEngine(t *testing.T) *Engine {
+ t.Helper()
+
+ engine, err := New(smokeOptions(t))
+ core.RequireNoError(t, err)
+ return engine
+}
+
+func smokeOptions(t *testing.T) corets.Options {
+ t.Helper()
+
+ denoPath := findDeno(t)
+ tempDir := t.TempDir()
+ runtimePath := core.PathJoin(tempDir, "runtime.ts")
+ writeResult := core.WriteFile(runtimePath, core.AsBytes(smokeRuntime), 0o600)
+ core.RequireTrue(t, writeResult.OK, writeResult.Error())
+
+ return corets.Options{
+ DenoPath: denoPath,
+ SocketPath: core.PathJoin(tempDir, "core.sock"),
+ DenoSocketPath: core.PathJoin(tempDir, "deno.sock"),
+ StoreDBPath: ":memory:",
+ SidecarArgs: []string{
+ "run",
+ "-A",
+ "--unstable-worker-options",
+ runtimePath,
+ },
+ }
+}
+
+func findDeno(t *testing.T) string {
+ t.Helper()
+
+ directories := core.Split(core.Env("PATH"), string(core.PathListSeparator))
+ if home := core.Env("DIR_HOME"); home != "" {
+ directories = append(directories, core.PathJoin(home, ".deno", "bin"))
+ }
+ for _, directory := range directories {
+ for _, name := range []string{"deno", "deno.exe"} {
+ candidate := core.PathJoin(directory, name)
+ if core.Stat(candidate).OK {
+ return candidate
+ }
+ }
+ }
+ t.Skip("deno not installed")
+ return ""
+}
+
+func inlineModule(source string) string {
+ return "data:application/typescript;base64," + core.Base64Encode(core.AsBytes(source))
+}
+
+const smokeRuntime = `
+const socketPath = Deno.env.get("DENO_SOCKET");
+if (!socketPath) throw new Error("DENO_SOCKET is required");
+try { await Deno.remove(socketPath); } catch (error) {
+ if (!(error instanceof Deno.errors.NotFound)) throw error;
+}
+
+const listener = Deno.listen({ transport: "unix", path: socketPath });
+const encoder = new TextEncoder();
+const decoder = new TextDecoder();
+
+for await (const connection of listener) {
+ void serve(connection);
+}
+
+async function serve(connection: Deno.Conn) {
+ let pending = "";
+ const buffer = new Uint8Array(64 * 1024);
+ try {
+ for (;;) {
+ const count = await connection.read(buffer);
+ if (count === null) return;
+ pending += decoder.decode(buffer.subarray(0, count), { stream: true });
+ for (;;) {
+ const newline = pending.indexOf("\n");
+ if (newline < 0) break;
+ const line = pending.slice(0, newline);
+ pending = pending.slice(newline + 1);
+ if (line.length === 0) continue;
+ const request = JSON.parse(line);
+ const result = await dispatch(request);
+ await connection.write(encoder.encode(JSON.stringify({
+ jsonrpc: "2.0",
+ id: request.id,
+ result,
+ }) + "\n"));
+ }
+ }
+ } finally {
+ connection.close();
+ }
+}
+
+async function dispatch(request: Record) {
+ switch (request.method) {
+ case "Ping":
+ return { ok: true };
+ case "LoadModule":
+ return await loadModule(
+ String(request.code ?? ""),
+ String(request.entry_point ?? ""),
+ (request.permissions ?? {}) as Record,
+ );
+ case "UnloadModule":
+ return { ok: true };
+ case "ModuleStatus":
+ return { code: String(request.code ?? ""), status: "RUNNING" };
+ default:
+ throw new Error("unknown method: " + request.method);
+ }
+}
+
+async function loadModule(
+ code: string,
+ entryPoint: string,
+ permissions: Record,
+) {
+ const workerSource = ` + "`" + `
+self.onmessage = async (event) => {
+ try {
+ const module = await import(event.data);
+ if (typeof module.init === "function") await module.init({});
+ self.postMessage({ ok: true });
+ } catch (error) {
+ self.postMessage({
+ ok: false,
+ error: error instanceof Error ? error.message : String(error),
+ });
+ }
+};
+` + "`" + `;
+ const workerURL = "data:application/javascript;base64," + btoa(workerSource);
+ const worker = new Worker(workerURL, {
+ type: "module",
+ name: code,
+ deno: {
+ permissions: {
+ read: permissions.read ?? [],
+ write: permissions.write ?? [],
+ net: permissions.net ?? [],
+ run: permissions.run ?? [],
+ env: false,
+ sys: false,
+ ffi: false,
+ },
+ },
+ });
+ try {
+ return await new Promise((resolve) => {
+ worker.onmessage = (event) => resolve(event.data);
+ worker.onerror = (event) => resolve({ ok: false, error: event.message });
+ worker.postMessage(entryPoint);
+ });
+ } finally {
+ worker.terminate();
+ }
+}
+`
diff --git a/go/go.mod b/go/go.mod
index 0fd00f3..362975c 100644
--- a/go/go.mod
+++ b/go/go.mod
@@ -10,7 +10,7 @@ require (
charm.land/lipgloss/v2 v2.0.5
dappco.re/go/i18n v0.12.1
dappco.re/go/io v0.15.1
- dappco.re/go/process v0.16.1
+ dappco.re/go/ts v0.2.2
github.com/charmbracelet/colorprofile v0.4.3
github.com/charmbracelet/harmonica v0.2.0
github.com/charmbracelet/ultraviolet v0.0.0-20260703014108-f5a850f9c2b7
@@ -27,7 +27,9 @@ require (
require (
dappco.re/go/log v0.13.1 // indirect
+ dappco.re/go/scm v0.22.0 // indirect
github.com/alecthomas/chroma/v2 v2.20.0 // indirect
+ github.com/apache/arrow-go/v18 v18.5.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymanbagabas/go-udiff v0.4.1 // indirect
@@ -51,17 +53,28 @@ require (
github.com/creack/pty v1.1.24 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
+ github.com/duckdb/duckdb-go-bindings v0.10504.0 // indirect
+ github.com/duckdb/duckdb-go-bindings/lib/darwin-amd64 v0.10504.0 // indirect
+ github.com/duckdb/duckdb-go-bindings/lib/darwin-arm64 v0.10504.0 // indirect
+ github.com/duckdb/duckdb-go-bindings/lib/linux-amd64 v0.10504.0 // indirect
+ github.com/duckdb/duckdb-go-bindings/lib/linux-arm64 v0.10504.0 // indirect
+ github.com/duckdb/duckdb-go-bindings/lib/windows-amd64 v0.10504.0 // indirect
+ github.com/duckdb/duckdb-go/v2 v2.10504.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.30.1 // indirect
+ github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/goccy/go-json v0.10.6 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
+ github.com/google/flatbuffers v25.12.19+incompatible // indirect
+ github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.18.4 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@@ -72,24 +85,32 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
+ github.com/pierrec/lz4/v4 v4.1.25 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
- github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/sahilm/fuzzy v0.1.3 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yuin/goldmark v1.7.13 // indirect
github.com/yuin/goldmark-emoji v1.0.6 // indirect
+ github.com/zeebo/xxh3 v1.1.0 // indirect
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
golang.org/x/arch v0.25.0 // indirect
- golang.org/x/crypto v0.50.0 // indirect
+ golang.org/x/crypto v0.53.0 // indirect
+ golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect
golang.org/x/image v0.44.0 // indirect
- golang.org/x/net v0.53.0 // indirect
+ golang.org/x/mod v0.37.0 // indirect
+ golang.org/x/net v0.56.0 // indirect
golang.org/x/sync v0.22.0 // indirect
golang.org/x/sys v0.46.0 // indirect
+ golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57 // indirect
+ golang.org/x/tools v0.47.0 // indirect
+ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
+ google.golang.org/grpc v1.79.3 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go/go.sum b/go/go.sum
index 9a685f6..8981a48 100644
--- a/go/go.sum
+++ b/go/go.sum
@@ -16,8 +16,10 @@ dappco.re/go/io v0.15.1 h1:HLrUG+uGVQgLfxeJRwMvf8VhTWe2CnAJWM4RBvs8HHo=
dappco.re/go/io v0.15.1/go.mod h1:I2kYHxtgactjcyih9TYQADA8jLE3NjfZHbwCVwQ3KyE=
dappco.re/go/log v0.13.1 h1:sfrB1hrxODsCo0A8psIvBqDkQD2mpoQ8S5S72zO2KlI=
dappco.re/go/log v0.13.1/go.mod h1:FBMMEdmIvbXfvv3qOdW6acFnwMFgTw56csevEIELi/c=
-dappco.re/go/process v0.16.1 h1:CMsiDrY7cMKd8B9UtUh0WIG9FkuNJ2wlz2x80KS20p4=
-dappco.re/go/process v0.16.1/go.mod h1:GgES0/Y75iRdrxbWizxyipf7fdz4W4LB+2Qp5Yu9Owk=
+dappco.re/go/scm v0.22.0 h1:V8K2T5uoIAcUoW9tZuJGlTtPBsV0rL9KwGtgspfsf84=
+dappco.re/go/scm v0.22.0/go.mod h1:v1y7kFJIOHwAJctm5OZ0aHjCX4Xz1E8YseUWShtVW2g=
+dappco.re/go/ts v0.2.2 h1:r+Lc+f3hCLBERFNidGsfO1K1GAbFjHrOJK4FTeOr1DA=
+dappco.re/go/ts v0.2.2/go.mod h1:YEV+/a09EKTOxRfx70++NYO0J4oaFN6C9MKWEqQvdqg=
forge.lthn.ai/Snider/Borg v0.3.1 h1:gfC1ZTpLoZai07oOWJiVeQ8+qJYK8A795tgVGJHbVL8=
forge.lthn.ai/Snider/Borg v0.3.1/go.mod h1:Z7DJD0yHXsxSyM7Mjl6/g4gH1NBsIz44Bf5AFlV76Wg=
forge.lthn.ai/Snider/Enchantrix v0.0.4 h1:biwpix/bdedfyc0iVeK15awhhJKH6TEMYOTXzHXx5TI=
@@ -32,6 +34,12 @@ github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NT
github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA=
github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg=
github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
+github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
+github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
+github.com/apache/arrow-go/v18 v18.5.1 h1:yaQ6zxMGgf9YCYw4/oaeOU3AULySDlAYDOcnr4LdHdI=
+github.com/apache/arrow-go/v18 v18.5.1/go.mod h1:OCCJsmdq8AsRm8FkBSSmYTwL/s4zHW9CqxeBxEytkNE=
+github.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc=
+github.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k=
@@ -70,6 +78,8 @@ github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiD
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
@@ -120,6 +130,20 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/duckdb/duckdb-go-bindings v0.10504.0 h1:XKOXNRetaJnMvMIDqi6etZOmh/nlEHM7saaC5UxU17I=
+github.com/duckdb/duckdb-go-bindings v0.10504.0/go.mod h1:M2eB9+zGq+O4opimtLL5nWwkp8vdJQJNbFW5HKdqe4U=
+github.com/duckdb/duckdb-go-bindings/lib/darwin-amd64 v0.10504.0 h1:hnWJ9SociR98hpypZPcgB+hTuWgw0hYsYnPFr8mBBEw=
+github.com/duckdb/duckdb-go-bindings/lib/darwin-amd64 v0.10504.0/go.mod h1:EnAvZh1kNJHp5yF+M1ZHNEvapnmt6anq1xXHVrAGqMo=
+github.com/duckdb/duckdb-go-bindings/lib/darwin-arm64 v0.10504.0 h1:q3JEdS5hU8ytvmcsgFEfGGQeJ5mS8l8QFYpfUlPHDRY=
+github.com/duckdb/duckdb-go-bindings/lib/darwin-arm64 v0.10504.0/go.mod h1:IGLSeEcFhNeZF16aVjQCULD7TsFZKG5G7SyKJAXKp5c=
+github.com/duckdb/duckdb-go-bindings/lib/linux-amd64 v0.10504.0 h1:2gABzYp2KnclSpE4qqinTZYhGpWSxmNHQKjs9WZ7zWk=
+github.com/duckdb/duckdb-go-bindings/lib/linux-amd64 v0.10504.0/go.mod h1:KAIynZ0GHCS7X5fRyuFnQMg/SZBPK/bS9OCOVojClxw=
+github.com/duckdb/duckdb-go-bindings/lib/linux-arm64 v0.10504.0 h1:iTFkIVt6Ohd/rTvNQomtbP/IIh90TFGSlOUqFEC68Xo=
+github.com/duckdb/duckdb-go-bindings/lib/linux-arm64 v0.10504.0/go.mod h1:81SGOYoEUs8qaAfSk1wRfM5oobrIJ5KI7AzYhK6/bvQ=
+github.com/duckdb/duckdb-go-bindings/lib/windows-amd64 v0.10504.0 h1:8O774uudYeexLa+uHekujkT3t3sDjQ7LSnlKIhRNWyc=
+github.com/duckdb/duckdb-go-bindings/lib/windows-amd64 v0.10504.0/go.mod h1:K25pJL26ARblGDeuAkrdblFvUen92+CwksLtPEHRqqQ=
+github.com/duckdb/duckdb-go/v2 v2.10504.0 h1:bnkcNQpz3EaJmMmfOhFRFJ3ELVDHW4u3PDhZ78ZTCMY=
+github.com/duckdb/duckdb-go/v2 v2.10504.0/go.mod h1:DQ8TxrUb0RGyTTFTwPNlpQ9FFx+ocJjoZGDkuOktYp8=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
@@ -128,6 +152,10 @@ github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
+github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
+github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -136,21 +164,35 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
+github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
+github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
+github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs=
+github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
+github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
+github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
+github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
@@ -171,6 +213,10 @@ github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/a
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
+github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
+github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
+github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
+github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -184,6 +230,8 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
+github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pkg/sftp v1.13.10 h1:+5FbKNTe5Z9aspU88DPIKJ9z2KZoaGCu6Sr6kKR/5mU=
github.com/pkg/sftp v1.13.10/go.mod h1:bJ1a7uDhrX/4OII+agvy28lzRvQrmIQuaHrcI1HbeGA=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -220,27 +268,57 @@ github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA=
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/yuin/goldmark-emoji v1.0.6 h1:QWfF2FYaXwL74tfGOW5izeiZepUDroDJfWubQI9HTHs=
github.com/yuin/goldmark-emoji v1.0.6/go.mod h1:ukxJDKFpdFb5x0a5HqbdlcKtebh086iJpI31LTKmWuA=
+github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
+github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
+github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
+github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
+go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
+go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
+go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
+go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
+go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
+go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
+go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
+go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
+go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
+go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
+go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
+go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE=
golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
-golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
-golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
+golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
+golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o=
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I=
golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY=
-golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
-golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
+golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
+golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57 h1:nwGZBCt+FnXUrGsj5vjzAsEmkcaFvd82BbOjECiFYZc=
+golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57/go.mod h1:3AWMyWHS+caVoiEXpiq6+tzKA40J4vQT3MYr80ZtQpc=
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
+golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
+golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
+golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
+golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
+gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
+gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
+google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=