From 94c4b8045bf69c4cf09ab5391f61411960e49c1f Mon Sep 17 00:00:00 2001 From: Spence Wetjen Date: Fri, 20 Feb 2026 03:30:21 +0000 Subject: [PATCH 1/3] Treat RawMessage as JSON and bump version to 0.0.21 --- CHANGELOG.md | 4 ++++ VERSION | 2 +- python_loader/pyproject.toml | 2 +- rpc/pgtype_test.go | 26 ++++++++++++++++++++++++++ schema/registry.go | 5 +++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0298a06..9f823ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.0.21 + +- Treat `encoding/json.RawMessage` as arbitrary JSON in generated schemas and clients instead of byte arrays. + ## 0.0.20 - Remove the unused `httpapi` lightweight JS client generator path. diff --git a/VERSION b/VERSION index cd23180..236c7ad 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.17 +0.0.21 diff --git a/python_loader/pyproject.toml b/python_loader/pyproject.toml index 2c41e2f..eb1610f 100644 --- a/python_loader/pyproject.toml +++ b/python_loader/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "virtuous" -version = "0.0.17" +version = "0.0.21" description = "Loader for Virtuous Python clients" readme = "README.md" requires-python = ">=3.12" diff --git a/rpc/pgtype_test.go b/rpc/pgtype_test.go index aaaf426..accb96b 100644 --- a/rpc/pgtype_test.go +++ b/rpc/pgtype_test.go @@ -133,6 +133,23 @@ func TestRPCPgtypeOpenAPIAndClients(t *testing.T) { t.Fatalf("OpenAPI missing schema %s", name) } } + for _, name := range []string{"pgtypeRequest", "pgtypeResponse"} { + root, ok := schemas[name].(map[string]any) + if !ok { + t.Fatalf("OpenAPI schema %s has unexpected type", name) + } + props, ok := root["properties"].(map[string]any) + if !ok { + t.Fatalf("OpenAPI schema %s missing properties", name) + } + raw, ok := props["raw"].(map[string]any) + if !ok { + t.Fatalf("OpenAPI schema %s missing raw property", name) + } + if raw["type"] != "object" { + t.Fatalf("OpenAPI raw type in %s = %v, want object", name, raw["type"]) + } + } var js bytes.Buffer if err := router.WriteClientJS(&js); err != nil { @@ -158,4 +175,13 @@ func TestRPCPgtypeOpenAPIAndClients(t *testing.T) { t.Fatalf("js client missing %s", name) } } + if !strings.Contains(ts.String(), "raw: any;") { + t.Fatalf("ts client should type raw as any") + } + if !strings.Contains(py.String(), "raw: Any") { + t.Fatalf("py client should type raw as Any") + } + if !strings.Contains(js.String(), "@property {any} raw") { + t.Fatalf("js client should type raw as any") + } } diff --git a/schema/registry.go b/schema/registry.go index 97cb38a..137d468 100644 --- a/schema/registry.go +++ b/schema/registry.go @@ -155,6 +155,11 @@ func defaultTypeOverrides() map[string]TypeOverride { OpenAPIType: "string", OpenAPIFormat: "date-time", }, + "encoding/json.RawMessage": { + JSType: "any", + PyType: "Any", + OpenAPIType: "object", + }, } } From fe591ad90204531c2af9c6cdac8c52ce37357968 Mon Sep 17 00:00:00 2001 From: Spence Wetjen Date: Sun, 22 Feb 2026 03:13:13 +0000 Subject: [PATCH 2/3] Document canonical Swaggo migration policy and version pinning --- docs/agents/overview.md | 2 ++ docs/overview.md | 3 +++ docs/tutorials/migrate-swaggo.md | 8 +++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/agents/overview.md b/docs/agents/overview.md index 5a5e987..8d6f774 100644 --- a/docs/agents/overview.md +++ b/docs/agents/overview.md @@ -15,6 +15,7 @@ Virtuous is designed to be deterministic for agents. Keep project layout and han ```text You are implementing a Virtuous RPC API. +- Target Virtuous version: read `VERSION` in the repo and pin it in the output (current: `0.0.21`). - Create router.go with rpc.NewRouter(rpc.WithPrefix("/rpc")). - Put handlers in package folders (states, users, admin). - Use func(ctx, req) (Resp, int). @@ -26,6 +27,7 @@ You are implementing a Virtuous RPC API. ```text Migrate Swaggo routes to Virtuous using the canonical guide at docs/tutorials/migrate-swaggo.md. +- Target Virtuous version: read `VERSION` in the repo and pin it in the output (current: `0.0.21`). - For Swaggo migrations, use httpapi first. - Use rpc only for explicit phase-2 moves. - Move field docs to doc struct tags. diff --git a/docs/overview.md b/docs/overview.md index 3abf1b3..de26cce 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -131,6 +131,7 @@ deps/ ```text You are implementing a Virtuous RPC API. +- Target Virtuous version: read `VERSION` in the repo and pin it in the output (current: `0.0.21`). - Create router.go with rpc.NewRouter(rpc.WithPrefix("/rpc")). - Put handlers in package folders (states, users, admin). - Use func(ctx, req) (Resp, int). @@ -142,6 +143,7 @@ You are implementing a Virtuous RPC API. ```text Use the canonical Swaggo migration prompt in docs/tutorials/migrate-swaggo.md. +- Target Virtuous version: read `VERSION` in the repo and pin it in the output (current: `0.0.21`). - Default to httpapi for Swaggo routes. - Use rpc only for phase-2 moves. - Validate against the migration Definition of Done in that guide. @@ -171,6 +173,7 @@ Agent prompt (porting legacy handlers): ```text Port legacy handlers into Virtuous. +- Target Virtuous version: read `VERSION` in the repo and pin it in the output (current: `0.0.21`). - For each handler, decide: RPC (new) or httpapi (legacy). - For legacy: wrap http.HandlerFunc with httpapi.WrapFunc and register a method-prefixed route. - For new: create an RPC handler and register with router.HandleRPC. diff --git a/docs/tutorials/migrate-swaggo.md b/docs/tutorials/migrate-swaggo.md index d23565f..7a43f56 100644 --- a/docs/tutorials/migrate-swaggo.md +++ b/docs/tutorials/migrate-swaggo.md @@ -175,6 +175,7 @@ Use this prompt for migration automation: You are migrating a Go API from Swaggo annotations to Virtuous. Goal: +- Pin the target Virtuous version from `VERSION` and report it explicitly (current: `0.0.21`). - Replace annotation-driven docs with Virtuous runtime docs/clients. - For Swaggo migrations, migrate routes to httpapi first. - Use RPC as an explicit phase-2 optimization after compatibility is preserved. @@ -191,9 +192,10 @@ Rules: Deliverables: 1) Code changes for migrated routes. -2) A migration completion checklist against the Definition of Done in docs/tutorials/migrate-swaggo.md. -3) List of routes intentionally deferred to phase-2 RPC and why. -4) Any routes blocked by feature mismatch, with concrete gap notes. +2) Reported target Virtuous version from `VERSION`. +3) A migration completion checklist against the Definition of Done in docs/tutorials/migrate-swaggo.md. +4) List of routes intentionally deferred to phase-2 RPC and why. +5) Any routes blocked by feature mismatch, with concrete gap notes. ``` ## Known gaps vs Swaggo From a9bcdf1c231c4c407dcf8c5fbdabf3a5423eea0c Mon Sep 17 00:00:00 2001 From: Spence Wetjen Date: Sun, 22 Feb 2026 03:14:56 +0000 Subject: [PATCH 3/3] better docs --- CHANGELOG.md | 5 ++ VERSION | 2 +- httpapi/docs.go | 155 +++++++++++++++++++++++------------ httpapi/docs_test.go | 22 +++++ python_loader/pyproject.toml | 2 +- rpc/docs.go | 155 +++++++++++++++++++++++------------ rpc/docs_test.go | 22 +++++ 7 files changed, 253 insertions(+), 110 deletions(-) create mode 100644 httpapi/docs_test.go create mode 100644 rpc/docs_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f823ee..70157c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.0.22 + +- Replace default Swagger UI docs pages with Scalar API Reference for both RPC and legacy HTTP routers. +- Preserve auth prefix behavior in docs by applying guard prefixes to outgoing request headers. + ## 0.0.21 - Treat `encoding/json.RawMessage` as arbitrary JSON in generated schemas and clients instead of byte arrays. diff --git a/VERSION b/VERSION index 236c7ad..818944f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.21 +0.0.22 diff --git a/httpapi/docs.go b/httpapi/docs.go index ac660a7..2ae264c 100644 --- a/httpapi/docs.go +++ b/httpapi/docs.go @@ -10,28 +10,65 @@ import ( "github.com/swetjen/virtuous/internal/textutil" ) -// DefaultDocsHTML returns a Swagger UI HTML page for the provided OpenAPI path. +// DefaultDocsHTML returns a Scalar API Reference HTML page for the provided OpenAPI path. func DefaultDocsHTML(openAPIPath string) string { return fmt.Sprintf(` + Virtuous API Docs - -
- +
+
+
+ `, openAPIPath) diff --git a/httpapi/docs_test.go b/httpapi/docs_test.go new file mode 100644 index 0000000..164dcac --- /dev/null +++ b/httpapi/docs_test.go @@ -0,0 +1,22 @@ +package httpapi + +import ( + "strings" + "testing" +) + +func TestDefaultDocsHTMLUsesScalar(t *testing.T) { + html := DefaultDocsHTML("/openapi.json") + if !strings.Contains(html, "https://cdn.jsdelivr.net/npm/@scalar/api-reference") { + t.Fatalf("expected Scalar script in docs HTML") + } + if !strings.Contains(html, "Scalar.createApiReference(\"#app\"") { + t.Fatalf("expected Scalar initialization in docs HTML") + } + if !strings.Contains(html, "const OPENAPI_URL = \"/openapi.json\"") { + t.Fatalf("expected openapi path in docs HTML") + } + if strings.Contains(html, "SwaggerUIBundle") { + t.Fatalf("unexpected Swagger UI bundle in docs HTML") + } +} diff --git a/python_loader/pyproject.toml b/python_loader/pyproject.toml index eb1610f..5363f69 100644 --- a/python_loader/pyproject.toml +++ b/python_loader/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "virtuous" -version = "0.0.21" +version = "0.0.22" description = "Loader for Virtuous Python clients" readme = "README.md" requires-python = ">=3.12" diff --git a/rpc/docs.go b/rpc/docs.go index db9a886..a9f8697 100644 --- a/rpc/docs.go +++ b/rpc/docs.go @@ -8,28 +8,65 @@ import ( "strings" ) -// DefaultDocsHTML returns a Swagger UI HTML page for the provided OpenAPI path. +// DefaultDocsHTML returns a Scalar API Reference HTML page for the provided OpenAPI path. func DefaultDocsHTML(openAPIPath string) string { return fmt.Sprintf(` + Virtuous RPC Docs - -
- +
+
+
+ `, openAPIPath) diff --git a/rpc/docs_test.go b/rpc/docs_test.go new file mode 100644 index 0000000..632c9e5 --- /dev/null +++ b/rpc/docs_test.go @@ -0,0 +1,22 @@ +package rpc + +import ( + "strings" + "testing" +) + +func TestDefaultDocsHTMLUsesScalar(t *testing.T) { + html := DefaultDocsHTML("/rpc/openapi.json") + if !strings.Contains(html, "https://cdn.jsdelivr.net/npm/@scalar/api-reference") { + t.Fatalf("expected Scalar script in docs HTML") + } + if !strings.Contains(html, "Scalar.createApiReference(\"#app\"") { + t.Fatalf("expected Scalar initialization in docs HTML") + } + if !strings.Contains(html, "const OPENAPI_URL = \"/rpc/openapi.json\"") { + t.Fatalf("expected openapi path in docs HTML") + } + if strings.Contains(html, "SwaggerUIBundle") { + t.Fatalf("unexpected Swagger UI bundle in docs HTML") + } +}