[gold] Add code generator for TypeScript RPC types.

Notes:
- Tryjob Infra-PerCommit-Lage will turn red upon any diffs on rpc_types.ts, forcing the backend/frontend types to stay in sync.
- This CL includes an initial set of types required by the upcoming lit-html/TypeScript search page.

Change-Id: I9c3de42c640ebc65995dda54fd430abb3a9d9ce1
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/302176
Reviewed-by: Joe Gregorio <jcgregorio@google.com>
Commit-Queue: Leandro Lovisolo <lovisolo@google.com>
diff --git a/golden/go/web/frontend/generate.go b/golden/go/web/frontend/generate.go
new file mode 100644
index 0000000..bd6e9e3
--- /dev/null
+++ b/golden/go/web/frontend/generate.go
@@ -0,0 +1,3 @@
+package frontend
+
+//go:generate go run ./generate_typescript_rpc_types -o ../../../modules/rpc_types.ts
diff --git a/golden/go/web/frontend/generate_typescript_rpc_types/main.go b/golden/go/web/frontend/generate_typescript_rpc_types/main.go
new file mode 100644
index 0000000..244f4c7
--- /dev/null
+++ b/golden/go/web/frontend/generate_typescript_rpc_types/main.go
@@ -0,0 +1,56 @@
+package main
+
+import (
+	"flag"
+	"io"
+
+	"github.com/skia-dev/go2ts"
+	"go.skia.org/infra/go/skerr"
+	"go.skia.org/infra/go/sklog"
+	"go.skia.org/infra/go/util"
+	search_frontend "go.skia.org/infra/golden/go/search/frontend"
+	"go.skia.org/infra/golden/go/status"
+	"go.skia.org/infra/golden/go/tiling"
+	"go.skia.org/infra/golden/go/web/frontend"
+)
+
+func main() {
+	var outputPath = flag.String("o", "", "Path to the output TypeScript file.")
+	flag.Parse()
+
+	generator := go2ts.New()
+	if err := addTypes(generator); err != nil {
+		sklog.Fatal(err)
+	}
+
+	err := util.WithWriteFile(*outputPath, func(w io.Writer) error {
+		return generator.Render(w)
+	})
+	if err != nil {
+		sklog.Fatal(err)
+	}
+}
+
+func addTypes(generator *go2ts.Go2TS) error {
+	// Response for the /json/changelist/{system}/{id} RPC endpoint.
+	if err := generator.AddWithName(frontend.ChangeListSummary{}, "ChangeListSummaryResponse"); err != nil {
+		return skerr.Wrap(err)
+	}
+
+	// Response for the /json/paramset RPC endpoint.
+	if err := generator.AddWithName(tiling.Tile{}.ParamSet, "ParamSetResponse"); err != nil {
+		return skerr.Wrap(err)
+	}
+
+	// Response for the /json/search RPC endpoint.
+	if err := generator.AddWithName(search_frontend.SearchResponse{}, "SearchResponse"); err != nil {
+		return skerr.Wrap(err)
+	}
+
+	// Response for the /json/trstatus RPC endpoint.
+	if err := generator.AddWithName(status.GUIStatus{}, "StatusResponse"); err != nil {
+		return skerr.Wrap(err)
+	}
+
+	return nil
+}
diff --git a/golden/modules/rpc_types.ts b/golden/modules/rpc_types.ts
new file mode 100644
index 0000000..d9c6c20
--- /dev/null
+++ b/golden/modules/rpc_types.ts
@@ -0,0 +1,140 @@
+// DO NOT EDIT. This file is automatically generated.
+
+export interface ChangeList {
+	system: string;
+	id: string;
+	owner: string;
+	status: string;
+	subject: string;
+	updated: string;
+	url: string;
+}
+
+export interface TryJob {
+	id: string;
+	name: string;
+	updated: string;
+	system: string;
+	url: string;
+}
+
+export interface PatchSet {
+	id: string;
+	order: number;
+	try_jobs: TryJob[] | null;
+}
+
+export interface ChangeListSummaryResponse {
+	cl: ChangeList;
+	patch_sets: PatchSet[] | null;
+	num_total_patch_sets: number;
+}
+
+export interface TriageHistory {
+	user: string;
+	ts: string;
+}
+
+export interface Trace {
+	label: TraceID;
+	data: number[] | null;
+	params: { [key: string]: string };
+	comment_indices: number[] | null;
+}
+
+export interface DigestStatus {
+	digest: Digest;
+	status: string;
+}
+
+export interface TraceGroup {
+	tileSize: number;
+	traces: Trace[] | null;
+	digests: DigestStatus[] | null;
+	total_digests: number;
+}
+
+export interface DiffMetrics {
+	numDiffPixels: number;
+	pixelDiffPercent: number;
+	maxRGBADiffs: number[];
+	dimDiffer: boolean;
+	diffs: { [key: string]: number };
+}
+
+export interface SRDiffDigest {
+	DiffMetrics: DiffMetrics | null;
+	digest: Digest;
+	status: string;
+	paramset: ParamSet;
+	n: number;
+}
+
+export interface SearchResult {
+	digest: Digest;
+	test: TestName;
+	status: string;
+	triage_history: TriageHistory[] | null;
+	paramset: ParamSet;
+	traces: TraceGroup;
+	refDiffs: { [key: string]: SRDiffDigest };
+	closestRef: RefClosest;
+}
+
+export interface Commit {
+	commit_time: number;
+	hash: string;
+	author: string;
+	message: string;
+	is_cl: boolean;
+}
+
+export interface TraceComment {
+	id: ID;
+	created_by: string;
+	updated_by: string;
+	created_ts: string;
+	updated_ts: string;
+	text: string;
+	query: ParamSet;
+}
+
+export interface SearchResponse {
+	digests: SearchResult[] | null;
+	offset: number;
+	size: number;
+	commits: Commit[] | null;
+	trace_comments: TraceComment[] | null;
+	bulk_triage_data: { [key: string]: { [key: string]: string } };
+}
+
+export interface GUICorpusStatus {
+	name: string;
+	ok: boolean;
+	minCommitHash: string;
+	untriagedCount: number;
+	negativeCount: number;
+}
+
+export interface StatusResponse {
+	ok: boolean;
+	firstCommit: Commit;
+	lastCommit: Commit;
+	totalCommits: number;
+	filledCommits: number;
+	corpStatus: GUICorpusStatus[] | null;
+}
+
+export type ParamSetResponse = { [key: string]: string[] };
+
+export type Digest = string;
+
+export type TestName = string;
+
+export type ParamSet = { [key: string]: string[] };
+
+export type TraceID = string;
+
+export type RefClosest = string;
+
+export type ID = string;