From b37d25e70d87126fdeaf39d2207f57e8fd744b51 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Wed, 18 Mar 2026 15:40:01 -0600 Subject: [PATCH 01/22] Add "exposed" operation for system nexus endpoint --- nexusannotations/v1/options.proto | 29 +++++++++++++++++++ temporal/api/workflowservice/v1/service.proto | 5 +++- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 nexusannotations/v1/options.proto diff --git a/nexusannotations/v1/options.proto b/nexusannotations/v1/options.proto new file mode 100644 index 000000000..0f817e4a4 --- /dev/null +++ b/nexusannotations/v1/options.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package nexus.v1; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/bergundy/nexus-proto-annotations/go/nexus/v1"; + +extend google.protobuf.ServiceOptions { + optional ServiceOptions service = 8233; +} + +extend google.protobuf.MethodOptions { + optional OperationOptions operation = 8234; +} + +message OperationOptions { + // Nexus operation name (defaults to proto method name). + string name = 1; + // Tags to attach to the operation. Used by code generators to include and exclude operations. + repeated string tags = 2; +} + +message ServiceOptions { + // Nexus service name (defaults to proto service full name). + string name = 1; + // Tags to attach to the service. Used by code generators to include and exclude services. + repeated string tags = 2; +} \ No newline at end of file diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index 8b0eb2ce6..7810aa7d8 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -10,8 +10,9 @@ option ruby_package = "Temporalio::Api::WorkflowService::V1"; option csharp_namespace = "Temporalio.Api.WorkflowService.V1"; -import "temporal/api/workflowservice/v1/request_response.proto"; import "google/api/annotations.proto"; +import "nexusannotations/v1/options.proto"; +import "temporal/api/workflowservice/v1/request_response.proto"; // WorkflowService API defines how Temporal SDKs and other clients interact with the Temporal server // to create and interact with workflows and activities. @@ -385,6 +386,8 @@ service WorkflowService { // (-- api-linter: core::0136::prepositions=disabled // aip.dev/not-precedent: "With" is used to indicate combined operation. --) rpc SignalWithStartWorkflowExecution (SignalWithStartWorkflowExecutionRequest) returns (SignalWithStartWorkflowExecutionResponse) { + option (nexus.v1.operation).tags = "exposed"; + option (google.api.http) = { post: "/namespaces/{namespace}/workflows/{workflow_id}/signal-with-start/{signal_name}" body: "*" From b51776406409a2abb55c0871515dcc2e1820aeea Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Wed, 18 Mar 2026 15:47:36 -0600 Subject: [PATCH 02/22] linter fixes --- nexusannotations/v1/options.proto | 2 +- temporal/api/workflowservice/v1/service.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nexusannotations/v1/options.proto b/nexusannotations/v1/options.proto index 0f817e4a4..a8ef63728 100644 --- a/nexusannotations/v1/options.proto +++ b/nexusannotations/v1/options.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package nexus.v1; +package nexusannotations.v1; import "google/protobuf/descriptor.proto"; diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index 53f4ce2db..9cd8b730d 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -488,7 +488,7 @@ service WorkflowService { // (-- api-linter: core::0136::prepositions=disabled // aip.dev/not-precedent: "With" is used to indicate combined operation. --) rpc SignalWithStartWorkflowExecution (SignalWithStartWorkflowExecutionRequest) returns (SignalWithStartWorkflowExecutionResponse) { - option (nexus.v1.operation).tags = "exposed"; + option (nexusannotations.v1.operation).tags = "exposed"; option (google.api.http) = { post: "/namespaces/{namespace}/workflows/{workflow_id}/signal-with-start/{signal_name}" From f0760b3a65d27f8c1ea8fe70f4797634cc24afc0 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Tue, 24 Mar 2026 12:56:09 -0600 Subject: [PATCH 03/22] remove local nexusannotations and use nexus-rpc repo --- nexusannotations/v1/options.proto | 29 ------------------- temporal/api/workflowservice/v1/service.proto | 2 +- 2 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 nexusannotations/v1/options.proto diff --git a/nexusannotations/v1/options.proto b/nexusannotations/v1/options.proto deleted file mode 100644 index a8ef63728..000000000 --- a/nexusannotations/v1/options.proto +++ /dev/null @@ -1,29 +0,0 @@ -syntax = "proto3"; - -package nexusannotations.v1; - -import "google/protobuf/descriptor.proto"; - -option go_package = "github.com/bergundy/nexus-proto-annotations/go/nexus/v1"; - -extend google.protobuf.ServiceOptions { - optional ServiceOptions service = 8233; -} - -extend google.protobuf.MethodOptions { - optional OperationOptions operation = 8234; -} - -message OperationOptions { - // Nexus operation name (defaults to proto method name). - string name = 1; - // Tags to attach to the operation. Used by code generators to include and exclude operations. - repeated string tags = 2; -} - -message ServiceOptions { - // Nexus service name (defaults to proto service full name). - string name = 1; - // Tags to attach to the service. Used by code generators to include and exclude services. - repeated string tags = 2; -} \ No newline at end of file diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index 9cd8b730d..7a0272ebd 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -11,7 +11,7 @@ option csharp_namespace = "Temporalio.Api.WorkflowService.V1"; import "google/api/annotations.proto"; -import "nexusannotations/v1/options.proto"; +import "nexus-rpc/nexus-proto-annotations/nexusannotations/v1/options.proto"; import "temporal/api/workflowservice/v1/request_response.proto"; import "temporal/api/protometa/v1/annotations.proto"; From 3f17a76966f2981481af4c835db197b2da7447bb Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Wed, 25 Mar 2026 14:15:41 -0600 Subject: [PATCH 04/22] add nexus annotations to buf.yaml --- buf.yaml | 1 + temporal/api/workflowservice/v1/service.proto | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/buf.yaml b/buf.yaml index e984c1439..83dacd99f 100644 --- a/buf.yaml +++ b/buf.yaml @@ -3,6 +3,7 @@ name: buf.build/temporalio/api deps: - buf.build/grpc-ecosystem/grpc-gateway - buf.build/googleapis/googleapis + - buf.build/temporalio/nexus-annotations build: excludes: # Buf won't accept a local dependency on the google protos but we need them diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index 7a0272ebd..ff9829271 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -11,9 +11,9 @@ option csharp_namespace = "Temporalio.Api.WorkflowService.V1"; import "google/api/annotations.proto"; -import "nexus-rpc/nexus-proto-annotations/nexusannotations/v1/options.proto"; -import "temporal/api/workflowservice/v1/request_response.proto"; +import "temporalio/nexus-annotations/nexusannotations/v1/options.proto"; import "temporal/api/protometa/v1/annotations.proto"; +import "temporal/api/workflowservice/v1/request_response.proto"; // WorkflowService API defines how Temporal SDKs and other clients interact with the Temporal server // to create and interact with workflows and activities. From ba43a5688afcda1b8b808b6213ad0f66fdf30bd9 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Wed, 25 Mar 2026 14:16:06 -0600 Subject: [PATCH 05/22] buf.lock --- buf.lock | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/buf.lock b/buf.lock index fccbfb89d..f43352bf2 100644 --- a/buf.lock +++ b/buf.lock @@ -4,10 +4,15 @@ deps: - remote: buf.build owner: googleapis repository: googleapis - commit: 28151c0d0a1641bf938a7672c500e01d - digest: shake256:49215edf8ef57f7863004539deff8834cfb2195113f0b890dd1f67815d9353e28e668019165b9d872395871eeafcbab3ccfdb2b5f11734d3cca95be9e8d139de + commit: 004180b77378443887d3b55cabc00384 + digest: shake256:d26c7c2fd95f0873761af33ca4a0c0d92c8577122b6feb74eb3b0a57ebe47a98ab24a209a0e91945ac4c77204e9da0c2de0020b2cedc27bdbcdea6c431eec69b - remote: buf.build owner: grpc-ecosystem repository: grpc-gateway - commit: 048ae6ff94ca4476b3225904b1078fad - digest: shake256:e5250bf2d999516c02206d757502b902e406f35c099d0e869dc3e4f923f6870fe0805a9974c27df0695462937eae90cd4d9db90bb9a03489412560baa74a87b6 + commit: 6467306b4f624747aaf6266762ee7a1c + digest: shake256:833d648b99b9d2c18b6882ef41aaeb113e76fc38de20dda810c588d133846e6593b4da71b388bcd921b1c7ab41c7acf8f106663d7301ae9e82ceab22cf64b1b7 + - remote: buf.build + owner: temporalio + repository: nexus-annotations + commit: 599b78404fbe4e78b833d527a1d0da40 + digest: shake256:1f41ef11ccbf31d7318b0fe1915550ba6567c99dc94694d60b117fc1ffc756290ba9766c58b403986f079e2b861b42538e5f8cf0495f744cd390d223b81854ca From ab1b41ddb7dbbff91a3bbb6fe25a8b24d92b92ed Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Wed, 25 Mar 2026 14:25:54 -0600 Subject: [PATCH 06/22] add target to Makefile for downloading updates --- Makefile | 7 ++++- buf.yaml | 2 ++ nexusannotations/v1/options.proto | 29 +++++++++++++++++++ temporal/api/workflowservice/v1/service.proto | 2 +- 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 nexusannotations/v1/options.proto diff --git a/Makefile b/Makefile index b4b33bdb5..3d9580d2a 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ ci-build: install proto http-api-docs install: grpc-install api-linter-install buf-install # Run all linters and compile proto files. -proto: grpc http-api-docs +proto: sync-nexus-annotations grpc http-api-docs ######################################################################## ##### Variables ###### @@ -95,6 +95,11 @@ buf-install: printf $(COLOR) "Install/update buf..." go install github.com/bufbuild/buf/cmd/buf@v1.27.0 +##### Sync external proto dependencies ##### +sync-nexus-annotations: + printf $(COLOR) "Sync nexusannotations from buf.build/temporalio/nexus-annotations..." + buf export buf.build/temporalio/nexus-annotations --output . + ##### Linters ##### api-linter: printf $(COLOR) "Run api-linter..." diff --git a/buf.yaml b/buf.yaml index 83dacd99f..6b9d9eb57 100644 --- a/buf.yaml +++ b/buf.yaml @@ -9,6 +9,8 @@ build: # Buf won't accept a local dependency on the google protos but we need them # to run api-linter, so just tell buf it ignore it - google + # Same for nexusannotations - local copy for api-linter, BSR dep for buf + - nexusannotations breaking: use: - WIRE_JSON diff --git a/nexusannotations/v1/options.proto b/nexusannotations/v1/options.proto new file mode 100644 index 000000000..e137896bb --- /dev/null +++ b/nexusannotations/v1/options.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package nexusannotations.v1; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/nexus-rpc/nexus-proto-annotations/go/nexusannotations/v1"; + +extend google.protobuf.ServiceOptions { + optional ServiceOptions service = 8233; +} + +extend google.protobuf.MethodOptions { + optional OperationOptions operation = 8234; +} + +message OperationOptions { + // Nexus operation name (defaults to proto method name). + string name = 1; + // Tags to attach to the operation. Used by code generators to include and exclude operations. + repeated string tags = 2; +} + +message ServiceOptions { + // Nexus service name (defaults to proto service full name). + string name = 1; + // Tags to attach to the service. Used by code generators to include and exclude services. + repeated string tags = 2; +} diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index ff9829271..4d814899f 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -11,7 +11,7 @@ option csharp_namespace = "Temporalio.Api.WorkflowService.V1"; import "google/api/annotations.proto"; -import "temporalio/nexus-annotations/nexusannotations/v1/options.proto"; +import "nexusannotations/v1/options.proto"; import "temporal/api/protometa/v1/annotations.proto"; import "temporal/api/workflowservice/v1/request_response.proto"; From 65d1c56e818166f509d47cda72df7f82779f4b48 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Fri, 3 Apr 2026 15:58:59 -0600 Subject: [PATCH 07/22] first draft of a nexusrpc{.langs}.yaml files --- Makefile | 14 +- cmd/protoc-gen-nexus-rpc-yaml/generator.go | 196 +++++++++++++++++++++ cmd/protoc-gen-nexus-rpc-yaml/go.mod | 10 ++ cmd/protoc-gen-nexus-rpc-yaml/go.sum | 12 ++ cmd/protoc-gen-nexus-rpc-yaml/main.go | 14 ++ nexus/nexusrpc.langs.yaml | 15 ++ nexus/nexusrpc.yaml | 9 + 7 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 cmd/protoc-gen-nexus-rpc-yaml/generator.go create mode 100644 cmd/protoc-gen-nexus-rpc-yaml/go.mod create mode 100644 cmd/protoc-gen-nexus-rpc-yaml/go.sum create mode 100644 cmd/protoc-gen-nexus-rpc-yaml/main.go create mode 100644 nexus/nexusrpc.langs.yaml create mode 100644 nexus/nexusrpc.yaml diff --git a/Makefile b/Makefile index 3d9580d2a..4a1b4055f 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ ci-build: install proto http-api-docs install: grpc-install api-linter-install buf-install # Run all linters and compile proto files. -proto: sync-nexus-annotations grpc http-api-docs +proto: sync-nexus-annotations grpc http-api-docs nexusrpc-yaml ######################################################################## ##### Variables ###### @@ -121,6 +121,18 @@ buf-breaking: @printf $(COLOR) "Run buf breaking changes check against master branch..." @(cd $(PROTO_ROOT) && buf breaking --against 'https://github.com/temporalio/api.git#branch=master') +nexusrpc-yaml: nexusrpc-yaml-install + printf $(COLOR) "Generate nexus/nexusrpc.yaml and nexus/nexusrpc.langs.yaml..." + mkdir -p nexus + protoc -I $(PROTO_ROOT) \ + --nexus-rpc-yaml_out=. \ + temporal/api/workflowservice/v1/* \ + temporal/api/operatorservice/v1/* + +nexusrpc-yaml-install: + printf $(COLOR) "Install protoc-gen-nexus-rpc-yaml..." + cd cmd/protoc-gen-nexus-rpc-yaml && go install . + ##### Clean ##### clean: printf $(COLOR) "Delete generated go files..." diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go new file mode 100644 index 000000000..39bbd117e --- /dev/null +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -0,0 +1,196 @@ +package main + +import ( + "slices" + "sort" + "strings" + + nexusannotationsv1 "github.com/nexus-rpc/nexus-proto-annotations/go/nexusannotations/v1" + "google.golang.org/protobuf/compiler/protogen" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/descriptorpb" + "gopkg.in/yaml.v3" +) + +func generate(gen *protogen.Plugin) error { + nexusDoc := newDoc() + langsDoc := newDoc() + + for _, f := range gen.Files { + if !f.Generate { + continue + } + for _, svc := range f.Services { + for _, m := range svc.Methods { + opts, ok := m.Desc.Options().(*descriptorpb.MethodOptions) + if !ok || opts == nil { + continue + } + if !proto.HasExtension(opts, nexusannotationsv1.E_Operation) { + continue + } + opOpts := proto.GetExtension(opts, nexusannotationsv1.E_Operation).(*nexusannotationsv1.OperationOptions) + if !slices.Contains(opOpts.GetTags(), "exposed") { + continue + } + + svcName := string(svc.Desc.Name()) + methodName := string(m.Desc.Name()) + + addOperation(nexusDoc, svcName, methodName, + map[string]string{"$ref": openAPIRef(m.Input.Desc)}, + map[string]string{"$ref": openAPIRef(m.Output.Desc)}, + ) + + addOperation(langsDoc, svcName, methodName, + langRefs(f.Desc, m.Input.Desc), + langRefs(f.Desc, m.Output.Desc), + ) + } + } + } + + if err := writeFile(gen, "nexus/nexusrpc.yaml", nexusDoc); err != nil { + return err + } + return writeFile(gen, "nexus/nexusrpc.langs.yaml", langsDoc) +} + +// openAPIRef returns the nexus-rpc-gen multi-file $ref string for a message type, +// referencing the openapiv3.yaml components/schemas entry. The path is relative to nexus/. +// +// Schema key convention used by protoc-gen-openapi (v3): +// +// {MessageName} (no package prefix) +// +// e.g. message "SignalWithStartWorkflowExecutionRequest" +// → "components.schemas.SignalWithStartWorkflowExecutionRequest" +func openAPIRef(msg protoreflect.MessageDescriptor) string { + return "../openapi/openapiv3.yaml#components.schemas." + string(msg.Name()) +} + +// langRefs builds the map of language-specific type refs for a message, +// derived from proto file-level options. Only keys with non-empty values are included. +// Order is canonical: go → java → ruby → csharp. +func langRefs(file protoreflect.FileDescriptor, msg protoreflect.MessageDescriptor) map[string]string { + opts, ok := file.Options().(*descriptorpb.FileOptions) + if !ok || opts == nil { + return nil + } + name := string(msg.Name()) + refs := make(map[string]string) + + if pkg := opts.GetGoPackage(); pkg != "" { + // strip the ";alias" suffix (e.g. "go.temporal.io/api/workflowservice/v1;workflowservice") + pkg = strings.SplitN(pkg, ";", 2)[0] + refs["$goRef"] = pkg + "." + name + } + if pkg := opts.GetJavaPackage(); pkg != "" { + refs["$javaRef"] = pkg + "." + name + } + if pkg := opts.GetRubyPackage(); pkg != "" { + refs["$rubyRef"] = pkg + "::" + name + } + if pkg := opts.GetCsharpNamespace(); pkg != "" { + refs["$csharpRef"] = pkg + "." + name + } + if len(refs) == 0 { + return nil + } + return refs +} + +// newDoc creates a yaml.Node document with the "nexusrpc: 1.0.0" header +// and an empty "services" mapping node, returned as a *yaml.Node (document node). +func newDoc() *yaml.Node { + doc := &yaml.Node{Kind: yaml.DocumentNode} + root := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + doc.Content = []*yaml.Node{root} + + root.Content = append(root.Content, + scalarNode("nexusrpc"), + scalarNode("1.0.0"), + scalarNode("services"), + &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}, + ) + return doc +} + +// servicesNode returns the "services" mapping node from a doc created by newDoc. +func servicesNode(doc *yaml.Node) *yaml.Node { + root := doc.Content[0] + for i := 0; i < len(root.Content)-1; i += 2 { + if root.Content[i].Value == "services" { + return root.Content[i+1] + } + } + panic("services node not found") +} + +// addOperation inserts a service → operation → {input, output} entry into doc. +// Services and operations are inserted in the order first encountered. +func addOperation(doc *yaml.Node, svcName, methodName string, input, output map[string]string) { + svcs := servicesNode(doc) + + // find or create service node + var svcOps *yaml.Node + for i := 0; i < len(svcs.Content)-1; i += 2 { + if svcs.Content[i].Value == svcName { + // find "operations" within service mapping + svcMap := svcs.Content[i+1] + for j := 0; j < len(svcMap.Content)-1; j += 2 { + if svcMap.Content[j].Value == "operations" { + svcOps = svcMap.Content[j+1] + } + } + } + } + if svcOps == nil { + svcMap := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + svcOps = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + svcMap.Content = append(svcMap.Content, + scalarNode("operations"), + svcOps, + ) + svcs.Content = append(svcs.Content, scalarNode(svcName), svcMap) + } + + // build operation node + opNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + if len(input) > 0 { + opNode.Content = append(opNode.Content, scalarNode("input"), mapNode(input)) + } + if len(output) > 0 { + opNode.Content = append(opNode.Content, scalarNode("output"), mapNode(output)) + } + svcOps.Content = append(svcOps.Content, scalarNode(methodName), opNode) +} + +// mapNode serializes a map[string]string as a yaml mapping node with keys in sorted order. +func mapNode(m map[string]string) *yaml.Node { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + node := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + for _, k := range keys { + node.Content = append(node.Content, scalarNode(k), scalarNode(m[k])) + } + return node +} + +func scalarNode(value string) *yaml.Node { + return &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: value} +} + +func writeFile(gen *protogen.Plugin, name string, doc *yaml.Node) error { + f := gen.NewGeneratedFile(name, "") + enc := yaml.NewEncoder(f) + enc.SetIndent(2) + if err := enc.Encode(doc); err != nil { + return err + } + return enc.Close() +} diff --git a/cmd/protoc-gen-nexus-rpc-yaml/go.mod b/cmd/protoc-gen-nexus-rpc-yaml/go.mod new file mode 100644 index 000000000..610f91712 --- /dev/null +++ b/cmd/protoc-gen-nexus-rpc-yaml/go.mod @@ -0,0 +1,10 @@ +module github.com/temporalio/api/cmd/protoc-gen-nexus-rpc-yaml + +go 1.25.4 + +require ( + google.golang.org/protobuf v1.36.1 + gopkg.in/yaml.v3 v3.0.1 +) + +require github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 diff --git a/cmd/protoc-gen-nexus-rpc-yaml/go.sum b/cmd/protoc-gen-nexus-rpc-yaml/go.sum new file mode 100644 index 000000000..f9fd894ce --- /dev/null +++ b/cmd/protoc-gen-nexus-rpc-yaml/go.sum @@ -0,0 +1,12 @@ +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 h1:SWHt3Coj0VvF0Km1A0wlY+IjnHKsjQLgO29io84r3wY= +github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84/go.mod h1:n3UjF1bPCW8llR8tHvbxJ+27yPWrhpo8w/Yg1IOuY0Y= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/protoc-gen-nexus-rpc-yaml/main.go b/cmd/protoc-gen-nexus-rpc-yaml/main.go new file mode 100644 index 000000000..9fadd0fb1 --- /dev/null +++ b/cmd/protoc-gen-nexus-rpc-yaml/main.go @@ -0,0 +1,14 @@ +// protoc-gen-nexus-rpc-yaml is a protoc plugin that generates nexus/nexusrpc.yaml +// and nexus/nexusrpc.langs.yaml from proto service methods annotated with +// option (nexusannotations.v1.operation).tags = "exposed". +package main + +import ( + "google.golang.org/protobuf/compiler/protogen" +) + +func main() { + protogen.Options{}.Run(func(gen *protogen.Plugin) error { + return generate(gen) + }) +} diff --git a/nexus/nexusrpc.langs.yaml b/nexus/nexusrpc.langs.yaml new file mode 100644 index 000000000..2262cf57d --- /dev/null +++ b/nexus/nexusrpc.langs.yaml @@ -0,0 +1,15 @@ +nexusrpc: 1.0.0 +services: + WorkflowService: + operations: + SignalWithStartWorkflowExecution: + input: + $csharpRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionRequest + $goRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionRequest + $javaRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest + $rubyRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionRequest + output: + $csharpRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionResponse + $goRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse + $javaRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse + $rubyRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionResponse diff --git a/nexus/nexusrpc.yaml b/nexus/nexusrpc.yaml new file mode 100644 index 000000000..08adb4b0b --- /dev/null +++ b/nexus/nexusrpc.yaml @@ -0,0 +1,9 @@ +nexusrpc: 1.0.0 +services: + WorkflowService: + operations: + SignalWithStartWorkflowExecution: + input: + $ref: ../openapi/openapiv3.yaml#components.schemas.SignalWithStartWorkflowExecutionRequest + output: + $ref: ../openapi/openapiv3.yaml#components.schemas.SignalWithStartWorkflowExecutionResponse From 9558edfb1c2642ff6983ce5421eac7e32f11c332 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Fri, 3 Apr 2026 16:14:21 -0600 Subject: [PATCH 08/22] use json pointer format instead of dot notation --- cmd/protoc-gen-nexus-rpc-yaml/generator.go | 4 ++-- nexus/nexusrpc.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go index 39bbd117e..53fa78fe5 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -65,9 +65,9 @@ func generate(gen *protogen.Plugin) error { // {MessageName} (no package prefix) // // e.g. message "SignalWithStartWorkflowExecutionRequest" -// → "components.schemas.SignalWithStartWorkflowExecutionRequest" +// → "../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionRequest" func openAPIRef(msg protoreflect.MessageDescriptor) string { - return "../openapi/openapiv3.yaml#components.schemas." + string(msg.Name()) + return "../openapi/openapiv3.yaml#/components/schemas/" + string(msg.Name()) } // langRefs builds the map of language-specific type refs for a message, diff --git a/nexus/nexusrpc.yaml b/nexus/nexusrpc.yaml index 08adb4b0b..bbfafb33a 100644 --- a/nexus/nexusrpc.yaml +++ b/nexus/nexusrpc.yaml @@ -4,6 +4,6 @@ services: operations: SignalWithStartWorkflowExecution: input: - $ref: ../openapi/openapiv3.yaml#components.schemas.SignalWithStartWorkflowExecutionRequest + $ref: ../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionRequest output: - $ref: ../openapi/openapiv3.yaml#components.schemas.SignalWithStartWorkflowExecutionResponse + $ref: ../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionResponse From d10e568cefc40a04c7866610682e63fde6378edc Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Mon, 6 Apr 2026 09:50:59 -0600 Subject: [PATCH 09/22] change file names --- cmd/protoc-gen-nexus-rpc-yaml/generator.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go index 53fa78fe5..24d959b2c 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -50,11 +50,10 @@ func generate(gen *protogen.Plugin) error { } } } - - if err := writeFile(gen, "nexus/nexusrpc.yaml", nexusDoc); err != nil { + if err := writeFile(gen, "nexus/temporal-json-schema-models-nexusrpc.yaml", nexusDoc); err != nil { return err } - return writeFile(gen, "nexus/nexusrpc.langs.yaml", langsDoc) + return writeFile(gen, "nexus/temporal-proto-models-nexusrpc.yaml", langsDoc) } // openAPIRef returns the nexus-rpc-gen multi-file $ref string for a message type, From d249bb64cd83c1f7abeaa98d27613be26a2593cf Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Mon, 6 Apr 2026 14:42:40 -0600 Subject: [PATCH 10/22] add typescript and python Refs --- cmd/protoc-gen-nexus-rpc-yaml/generator.go | 16 ++++++++++++---- ...=> temporal-json-schema-models-nexusrpc.yaml} | 0 ....yaml => temporal-proto-models-nexusrpc.yaml} | 8 ++++++-- 3 files changed, 18 insertions(+), 6 deletions(-) rename nexus/{nexusrpc.yaml => temporal-json-schema-models-nexusrpc.yaml} (100%) rename nexus/{nexusrpc.langs.yaml => temporal-proto-models-nexusrpc.yaml} (59%) diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go index 24d959b2c..0cf0e0c7d 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -69,9 +69,10 @@ func openAPIRef(msg protoreflect.MessageDescriptor) string { return "../openapi/openapiv3.yaml#/components/schemas/" + string(msg.Name()) } -// langRefs builds the map of language-specific type refs for a message, -// derived from proto file-level options. Only keys with non-empty values are included. -// Order is canonical: go → java → ruby → csharp. +// langRefs builds the map of language-specific type refs for a message. +// Go, Java, dotnet, and Ruby refs are derived from proto file-level package options. +// Python and TypeScript refs are derived from the go_package path, taking only the +// last two path segments ({service}/v{n}). func langRefs(file protoreflect.FileDescriptor, msg protoreflect.MessageDescriptor) map[string]string { opts, ok := file.Options().(*descriptorpb.FileOptions) if !ok || opts == nil { @@ -84,6 +85,13 @@ func langRefs(file protoreflect.FileDescriptor, msg protoreflect.MessageDescript // strip the ";alias" suffix (e.g. "go.temporal.io/api/workflowservice/v1;workflowservice") pkg = strings.SplitN(pkg, ";", 2)[0] refs["$goRef"] = pkg + "." + name + + segments := strings.Split(pkg, "/") + if len(segments) >= 2 { + tail := strings.Join(segments[len(segments)-2:], "/") + refs["$pythonRef"] = "temporalio.api." + strings.ReplaceAll(tail, "/", ".") + "." + name + refs["$typescriptRef"] = "@temporalio/api/" + tail + "." + name + } } if pkg := opts.GetJavaPackage(); pkg != "" { refs["$javaRef"] = pkg + "." + name @@ -92,7 +100,7 @@ func langRefs(file protoreflect.FileDescriptor, msg protoreflect.MessageDescript refs["$rubyRef"] = pkg + "::" + name } if pkg := opts.GetCsharpNamespace(); pkg != "" { - refs["$csharpRef"] = pkg + "." + name + refs["$dotnetRef"] = pkg + "." + name } if len(refs) == 0 { return nil diff --git a/nexus/nexusrpc.yaml b/nexus/temporal-json-schema-models-nexusrpc.yaml similarity index 100% rename from nexus/nexusrpc.yaml rename to nexus/temporal-json-schema-models-nexusrpc.yaml diff --git a/nexus/nexusrpc.langs.yaml b/nexus/temporal-proto-models-nexusrpc.yaml similarity index 59% rename from nexus/nexusrpc.langs.yaml rename to nexus/temporal-proto-models-nexusrpc.yaml index 2262cf57d..e0761fd15 100644 --- a/nexus/nexusrpc.langs.yaml +++ b/nexus/temporal-proto-models-nexusrpc.yaml @@ -4,12 +4,16 @@ services: operations: SignalWithStartWorkflowExecution: input: - $csharpRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionRequest + $dotnetRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionRequest $goRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionRequest $javaRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest + $pythonRef: temporalio.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest $rubyRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionRequest + $typescriptRef: '@temporalio/api/workflowservice/v1.SignalWithStartWorkflowExecutionRequest' output: - $csharpRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionResponse + $dotnetRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionResponse $goRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse $javaRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse + $pythonRef: temporalio.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse $rubyRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionResponse + $typescriptRef: '@temporalio/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse' From 1152ac57012cadc51657f87c38110d862d193883 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Mon, 13 Apr 2026 12:52:14 -0600 Subject: [PATCH 11/22] addressing review comments --- Makefile | 6 + cmd/protoc-gen-nexus-rpc-yaml/generator.go | 189 ++++++++++++++++----- 2 files changed, 150 insertions(+), 45 deletions(-) diff --git a/Makefile b/Makefile index 4a1b4055f..aac952788 100644 --- a/Makefile +++ b/Makefile @@ -125,6 +125,12 @@ nexusrpc-yaml: nexusrpc-yaml-install printf $(COLOR) "Generate nexus/nexusrpc.yaml and nexus/nexusrpc.langs.yaml..." mkdir -p nexus protoc -I $(PROTO_ROOT) \ + --nexus-rpc-yaml_opt=openapi_ref_prefix=../openapi/openapiv3.yaml#/components/schemas/ \ + --nexus-rpc-yaml_opt=nexusrpc_out=nexus/temporal-json-schema-models-nexusrpc.yaml \ + --nexus-rpc-yaml_opt=nexusrpc_langs_out=nexus/temporal-proto-models-nexusrpc.yaml \ + --nexus-rpc-yaml_opt=python_package_prefix=temporalio.api \ + --nexus-rpc-yaml_opt=typescript_package_prefix=@temporalio/api \ + --nexus-rpc-yaml_opt=include_operation_tags=exposed \ --nexus-rpc-yaml_out=. \ temporal/api/workflowservice/v1/* \ temporal/api/operatorservice/v1/* diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go index 0cf0e0c7d..9d2ecb5ca 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "slices" "sort" "strings" @@ -13,9 +14,115 @@ import ( "gopkg.in/yaml.v3" ) +// params holds the parsed protoc plugin options. +// Passed via --nexus-rpc-yaml_opt=key=value (multiple opts are comma-joined by protoc). +// +// - openapi_ref_prefix: optional. Prefix prepended to the message name to form the +// JSON Schema $ref in nexusrpc.yaml. If empty, nexusrpc.yaml is not written. +// Example: "../openapi/openapiv3.yaml#/components/schemas/" +// +// - nexusrpc_out: optional. Output path for nexusrpc.yaml (relative to --nexus-rpc-yaml_out dir). +// If empty, nexusrpc.yaml is not written. Requires openapi_ref_prefix to also be set. +// Example: "nexus/nexusrpc.yaml" +// +// - nexusrpc_langs_out: optional. Output path for nexusrpc.langs.yaml. +// If empty, nexusrpc.langs.yaml is not written. +// Example: "nexus/nexusrpc.langs.yaml" +// +// - python_package_prefix: optional. Dot-separated package prefix for $pythonRef. +// The last two path segments of the go_package ({service}/v{n}) are appended. +// Example: "temporalio.api" → "temporalio.api.workflowservice.v1.TypeName" +// If empty, $pythonRef is omitted. +// +// - typescript_package_prefix: optional. Scoped package prefix for $typescriptRef. +// The last two path segments of the go_package ({service}/v{n}) are appended. +// Example: "@temporalio/api" → "@temporalio/api/workflowservice/v1.TypeName" +// If empty, $typescriptRef is omitted. +// +// - include_operation_tags: optional, repeatable. Only include operations whose tags +// contain at least one of these values. If empty, all annotated operations are included +// (subject to exclude_operation_tags). Specify multiple times for multiple tags. +// Example: include_operation_tags=exposed +// +// - exclude_operation_tags: optional, repeatable. Exclude operations whose tags contain +// any of these values. Applied after include_operation_tags. +// Example: exclude_operation_tags=internal +type params struct { + openAPIRefPrefix string + nexusrpcOut string + nexusrpcLangsOut string + pythonPackagePrefix string + typescriptPackagePrefix string + includeOperationTags []string + excludeOperationTags []string +} + +// parseParams parses the comma-separated key=value parameter string provided by protoc. +func parseParams(raw string) (params, error) { + var p params + if raw == "" { + return p, nil + } + for kv := range strings.SplitSeq(raw, ",") { + key, value, ok := strings.Cut(kv, "=") + if !ok { + return p, fmt.Errorf("invalid parameter %q: expected key=value", kv) + } + switch key { + case "openapi_ref_prefix": + p.openAPIRefPrefix = value + case "nexusrpc_out": + p.nexusrpcOut = value + case "nexusrpc_langs_out": + p.nexusrpcLangsOut = value + case "python_package_prefix": + p.pythonPackagePrefix = value + case "typescript_package_prefix": + p.typescriptPackagePrefix = value + case "include_operation_tags": + p.includeOperationTags = append(p.includeOperationTags, value) + case "exclude_operation_tags": + p.excludeOperationTags = append(p.excludeOperationTags, value) + default: + return p, fmt.Errorf("unknown parameter %q", key) + } + } + return p, nil +} + +// shouldIncludeOperation returns true if the method's nexus operation tags pass +// the include/exclude filters. Mirrors the logic from protoc-gen-go-nexus: +// 1. Method must have the nexus operation extension set. +// 2. If includeOperationTags is non-empty, at least one of the method's tags must match. +// 3. If excludeOperationTags is non-empty, none of the method's tags may match. +func shouldIncludeOperation(p params, m *protogen.Method) bool { + opts, ok := m.Desc.Options().(*descriptorpb.MethodOptions) + if !ok || opts == nil { + return false + } + if !proto.HasExtension(opts, nexusannotationsv1.E_Operation) { + return false + } + tags := proto.GetExtension(opts, nexusannotationsv1.E_Operation).(*nexusannotationsv1.OperationOptions).GetTags() + if len(p.includeOperationTags) > 0 && !slices.ContainsFunc(p.includeOperationTags, func(t string) bool { + return slices.Contains(tags, t) + }) { + return false + } + return !slices.ContainsFunc(p.excludeOperationTags, func(t string) bool { + return slices.Contains(tags, t) + }) +} + func generate(gen *protogen.Plugin) error { + p, err := parseParams(gen.Request.GetParameter()) + if err != nil { + return err + } + nexusDoc := newDoc() langsDoc := newDoc() + hasOps := false for _, f := range gen.Files { if !f.Generate { @@ -23,57 +130,51 @@ func generate(gen *protogen.Plugin) error { } for _, svc := range f.Services { for _, m := range svc.Methods { - opts, ok := m.Desc.Options().(*descriptorpb.MethodOptions) - if !ok || opts == nil { - continue - } - if !proto.HasExtension(opts, nexusannotationsv1.E_Operation) { - continue - } - opOpts := proto.GetExtension(opts, nexusannotationsv1.E_Operation).(*nexusannotationsv1.OperationOptions) - if !slices.Contains(opOpts.GetTags(), "exposed") { + if !shouldIncludeOperation(p, m) { continue } svcName := string(svc.Desc.Name()) methodName := string(m.Desc.Name()) + hasOps = true - addOperation(nexusDoc, svcName, methodName, - map[string]string{"$ref": openAPIRef(m.Input.Desc)}, - map[string]string{"$ref": openAPIRef(m.Output.Desc)}, - ) + if p.openAPIRefPrefix != "" { + addOperation(nexusDoc, svcName, methodName, + map[string]string{"$ref": p.openAPIRefPrefix + string(m.Input.Desc.Name())}, + map[string]string{"$ref": p.openAPIRefPrefix + string(m.Output.Desc.Name())}, + ) + } addOperation(langsDoc, svcName, methodName, - langRefs(f.Desc, m.Input.Desc), - langRefs(f.Desc, m.Output.Desc), + langRefs(p, f.Desc, m.Input.Desc), + langRefs(p, f.Desc, m.Output.Desc), ) } } } - if err := writeFile(gen, "nexus/temporal-json-schema-models-nexusrpc.yaml", nexusDoc); err != nil { - return err + + if !hasOps { + return nil } - return writeFile(gen, "nexus/temporal-proto-models-nexusrpc.yaml", langsDoc) -} -// openAPIRef returns the nexus-rpc-gen multi-file $ref string for a message type, -// referencing the openapiv3.yaml components/schemas entry. The path is relative to nexus/. -// -// Schema key convention used by protoc-gen-openapi (v3): -// -// {MessageName} (no package prefix) -// -// e.g. message "SignalWithStartWorkflowExecutionRequest" -// → "../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionRequest" -func openAPIRef(msg protoreflect.MessageDescriptor) string { - return "../openapi/openapiv3.yaml#/components/schemas/" + string(msg.Name()) + if p.openAPIRefPrefix != "" && p.nexusrpcOut != "" { + if err := writeFile(gen, p.nexusrpcOut, nexusDoc); err != nil { + return err + } + } + if p.nexusrpcLangsOut != "" { + return writeFile(gen, p.nexusrpcLangsOut, langsDoc) + } + return nil } // langRefs builds the map of language-specific type refs for a message. +// // Go, Java, dotnet, and Ruby refs are derived from proto file-level package options. -// Python and TypeScript refs are derived from the go_package path, taking only the -// last two path segments ({service}/v{n}). -func langRefs(file protoreflect.FileDescriptor, msg protoreflect.MessageDescriptor) map[string]string { +// Python and TypeScript refs require the corresponding prefix params to be set; if +// empty they are omitted. Both use the last two path segments of go_package +// ({service}/v{n}), dropping any intermediate grouping directory. +func langRefs(p params, file protoreflect.FileDescriptor, msg protoreflect.MessageDescriptor) map[string]string { opts, ok := file.Options().(*descriptorpb.FileOptions) if !ok || opts == nil { return nil @@ -88,9 +189,14 @@ func langRefs(file protoreflect.FileDescriptor, msg protoreflect.MessageDescript segments := strings.Split(pkg, "/") if len(segments) >= 2 { - tail := strings.Join(segments[len(segments)-2:], "/") - refs["$pythonRef"] = "temporalio.api." + strings.ReplaceAll(tail, "/", ".") + "." + name - refs["$typescriptRef"] = "@temporalio/api/" + tail + "." + name + tail := segments[len(segments)-2] + "/" + segments[len(segments)-1] + if p.pythonPackagePrefix != "" { + dotTail := strings.ReplaceAll(tail, "/", ".") + refs["$pythonRef"] = p.pythonPackagePrefix + "." + dotTail + "." + name + } + if p.typescriptPackagePrefix != "" { + refs["$typescriptRef"] = p.typescriptPackagePrefix + "/" + tail + "." + name + } } } if pkg := opts.GetJavaPackage(); pkg != "" { @@ -109,12 +215,11 @@ func langRefs(file protoreflect.FileDescriptor, msg protoreflect.MessageDescript } // newDoc creates a yaml.Node document with the "nexusrpc: 1.0.0" header -// and an empty "services" mapping node, returned as a *yaml.Node (document node). +// and an empty "services" mapping node. func newDoc() *yaml.Node { doc := &yaml.Node{Kind: yaml.DocumentNode} root := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} doc.Content = []*yaml.Node{root} - root.Content = append(root.Content, scalarNode("nexusrpc"), scalarNode("1.0.0"), @@ -140,11 +245,9 @@ func servicesNode(doc *yaml.Node) *yaml.Node { func addOperation(doc *yaml.Node, svcName, methodName string, input, output map[string]string) { svcs := servicesNode(doc) - // find or create service node var svcOps *yaml.Node for i := 0; i < len(svcs.Content)-1; i += 2 { if svcs.Content[i].Value == svcName { - // find "operations" within service mapping svcMap := svcs.Content[i+1] for j := 0; j < len(svcMap.Content)-1; j += 2 { if svcMap.Content[j].Value == "operations" { @@ -156,14 +259,10 @@ func addOperation(doc *yaml.Node, svcName, methodName string, input, output map[ if svcOps == nil { svcMap := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} svcOps = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - svcMap.Content = append(svcMap.Content, - scalarNode("operations"), - svcOps, - ) + svcMap.Content = append(svcMap.Content, scalarNode("operations"), svcOps) svcs.Content = append(svcs.Content, scalarNode(svcName), svcMap) } - // build operation node opNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} if len(input) > 0 { opNode.Content = append(opNode.Content, scalarNode("input"), mapNode(input)) From c2673983c3203174c1c0a8e660a9bc5d52268d26 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Mon, 13 Apr 2026 13:54:21 -0600 Subject: [PATCH 12/22] install from nexus-rpc/nexus-rpc-gen repo --- Makefile | 24 ++++++++++++++---------- cmd/protoc-gen-nexus-rpc-yaml/go.mod | 7 ++++++- cmd/protoc-gen-nexus-rpc-yaml/go.sum | 16 ++++++++++++---- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index aac952788..e069f75fd 100644 --- a/Makefile +++ b/Makefile @@ -122,22 +122,26 @@ buf-breaking: @(cd $(PROTO_ROOT) && buf breaking --against 'https://github.com/temporalio/api.git#branch=master') nexusrpc-yaml: nexusrpc-yaml-install - printf $(COLOR) "Generate nexus/nexusrpc.yaml and nexus/nexusrpc.langs.yaml..." + printf $(COLOR) "Generate nexus/temporal-json-schema-models-nexusrpc.yaml and nexus/temporal-proto-models-nexusrpc.yaml..." mkdir -p nexus protoc -I $(PROTO_ROOT) \ - --nexus-rpc-yaml_opt=openapi_ref_prefix=../openapi/openapiv3.yaml#/components/schemas/ \ - --nexus-rpc-yaml_opt=nexusrpc_out=nexus/temporal-json-schema-models-nexusrpc.yaml \ - --nexus-rpc-yaml_opt=nexusrpc_langs_out=nexus/temporal-proto-models-nexusrpc.yaml \ - --nexus-rpc-yaml_opt=python_package_prefix=temporalio.api \ - --nexus-rpc-yaml_opt=typescript_package_prefix=@temporalio/api \ - --nexus-rpc-yaml_opt=include_operation_tags=exposed \ - --nexus-rpc-yaml_out=. \ + --nexusrpc_opt=openapi_ref_prefix=../openapi/openapiv3.yaml#/components/schemas/ \ + --nexusrpc_opt=nexusrpc_out=nexus/temporal-json-schema-models-nexusrpc.yaml \ + --nexusrpc_opt=nexusrpc_langs_out=nexus/temporal-proto-models-nexusrpc.yaml \ + --nexusrpc_opt=python_package_prefix=temporalio.api \ + --nexusrpc_opt=typescript_package_prefix=@temporalio/api \ + --nexusrpc_opt=include_operation_tags=exposed \ + --nexusrpc_out=. \ temporal/api/workflowservice/v1/* \ temporal/api/operatorservice/v1/* nexusrpc-yaml-install: - printf $(COLOR) "Install protoc-gen-nexus-rpc-yaml..." - cd cmd/protoc-gen-nexus-rpc-yaml && go install . + # TODO seankane: after merging nexus-rpc/nexus-rpc-gen#36 update this to install from `main` instead of branch + printf $(COLOR) "Install protoc-gen-nexusrpc from nexus-rpc/nexus-rpc-gen@spk/protoc-plugin..." + @NEXUSRPC_TMP=$$(mktemp -d) && \ + git clone --quiet --depth=1 --branch=spk/protoc-plugin https://github.com/nexus-rpc/nexus-rpc-gen.git $$NEXUSRPC_TMP && \ + cd $$NEXUSRPC_TMP/tools/protoc-gen-nexusrpc && go install ./cmd/protoc-gen-nexusrpc && \ + rm -rf $$NEXUSRPC_TMP ##### Clean ##### clean: diff --git a/cmd/protoc-gen-nexus-rpc-yaml/go.mod b/cmd/protoc-gen-nexus-rpc-yaml/go.mod index 610f91712..c507d8486 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/go.mod +++ b/cmd/protoc-gen-nexus-rpc-yaml/go.mod @@ -7,4 +7,9 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) -require github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 +require ( + github.com/bufbuild/protocompile v0.14.1 + github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 +) + +require golang.org/x/sync v0.8.0 // indirect diff --git a/cmd/protoc-gen-nexus-rpc-yaml/go.sum b/cmd/protoc-gen-nexus-rpc-yaml/go.sum index f9fd894ce..c248e2ac6 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/go.sum +++ b/cmd/protoc-gen-nexus-rpc-yaml/go.sum @@ -1,9 +1,17 @@ -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= +github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 h1:SWHt3Coj0VvF0Km1A0wlY+IjnHKsjQLgO29io84r3wY= github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84/go.mod h1:n3UjF1bPCW8llR8tHvbxJ+27yPWrhpo8w/Yg1IOuY0Y= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From c3e6d2663868b65987aeda209f789231c1b22e31 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Tue, 14 Apr 2026 11:59:14 -0600 Subject: [PATCH 13/22] tests --- .../generator_test.go | 162 ++++++++++++++++++ .../testdata/nexusrpc.yaml | 9 + .../testdata/nexusrpc_langs.yaml | 19 ++ .../testdata/test/v1/service.proto | 21 +++ 4 files changed, 211 insertions(+) create mode 100644 cmd/protoc-gen-nexus-rpc-yaml/generator_test.go create mode 100644 cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc.yaml create mode 100644 cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc_langs.yaml create mode 100644 cmd/protoc-gen-nexus-rpc-yaml/testdata/test/v1/service.proto diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator_test.go b/cmd/protoc-gen-nexus-rpc-yaml/generator_test.go new file mode 100644 index 000000000..78d7374f1 --- /dev/null +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator_test.go @@ -0,0 +1,162 @@ +package main + +import ( + "context" + "os" + "testing" + + "github.com/bufbuild/protocompile" + nexusannotationsv1 "github.com/nexus-rpc/nexus-proto-annotations/go/nexusannotations/v1" + "google.golang.org/protobuf/compiler/protogen" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protodesc" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/pluginpb" +) + +// runGenerate compiles testdata/test/v1/service.proto using the given plugin +// parameter string and returns the generated file contents keyed by filename. +// +// Known dependencies (google/protobuf/descriptor.proto and +// nexusannotations/v1/options.proto) are supplied as pre-compiled Go +// descriptors so that extension values are deserialized into Go-generated +// types rather than *dynamicpb.Message. +func runGenerate(t *testing.T, parameter string) map[string]string { + t.Helper() + + resolver := protocompile.CompositeResolver{ + // Return pre-compiled Go file descriptors for known dependencies. + // This ensures that the nexus extension is deserialised into the + // Go-generated *nexusannotationsv1.OperationOptions type, not a + // dynamic protobuf message, which would cause a type-assertion panic + // in shouldIncludeOperation. + protocompile.ResolverFunc(func(path string) (protocompile.SearchResult, error) { + switch path { + case "google/protobuf/descriptor.proto": + return protocompile.SearchResult{Desc: descriptorpb.File_google_protobuf_descriptor_proto}, nil + case "nexusannotations/v1/options.proto": + return protocompile.SearchResult{Desc: nexusannotationsv1.File_nexusannotations_v1_options_proto}, nil + } + return protocompile.SearchResult{}, protoregistry.NotFound + }), + // Fall back to reading source files from the testdata directory. + &protocompile.SourceResolver{ImportPaths: []string{"testdata"}}, + } + + compiledFiles, err := (&protocompile.Compiler{Resolver: resolver}).Compile( + context.Background(), "test/v1/service.proto", + ) + if err != nil { + t.Fatalf("compiling test proto: %v", err) + } + + // Collect all file descriptor protos in topological order (imports before importers). + // Each FileDescriptorProto is round-tripped through proto.Marshal + proto.Unmarshal + // to normalize extension fields. protocompile stores extension values as + // *dynamicpb.Message objects; the round-trip serializes them to raw bytes and lets + // proto.Unmarshal deserialize them as the registered Go-generated types (e.g. + // *nexusannotationsv1.OperationOptions). Without this, proto.GetExtension in the + // generator would panic with "invalid type: got *dynamicpb.Message". + seen := make(map[string]bool) + var protoFiles []*descriptorpb.FileDescriptorProto + var collect func(f protoreflect.FileDescriptor) + collect = func(f protoreflect.FileDescriptor) { + if seen[f.Path()] { + return + } + seen[f.Path()] = true + for i := 0; i < f.Imports().Len(); i++ { + collect(f.Imports().Get(i)) + } + raw, err := proto.Marshal(protodesc.ToFileDescriptorProto(f)) + if err != nil { + t.Fatalf("marshaling file descriptor %s: %v", f.Path(), err) + } + var fdp descriptorpb.FileDescriptorProto + if err := proto.Unmarshal(raw, &fdp); err != nil { + t.Fatalf("unmarshaling file descriptor %s: %v", f.Path(), err) + } + protoFiles = append(protoFiles, &fdp) + } + for _, f := range compiledFiles { + collect(f) + } + + req := &pluginpb.CodeGeneratorRequest{ + FileToGenerate: []string{"test/v1/service.proto"}, + ProtoFile: protoFiles, + Parameter: proto.String(parameter), + } + gen, err := protogen.Options{}.New(req) + if err != nil { + t.Fatalf("creating plugin: %v", err) + } + if err := generate(gen); err != nil { + t.Fatalf("generate: %v", err) + } + + result := make(map[string]string) + for _, f := range gen.Response().File { + result[f.GetName()] = f.GetContent() + } + return result +} + +// compareGolden compares got against the contents of goldenPath. +// Set UPDATE_GOLDEN=1 to overwrite the golden file with the current output +// instead of comparing, making it easy to refresh after intentional generator changes. +func compareGolden(t *testing.T, got, goldenPath string) { + t.Helper() + if os.Getenv("UPDATE_GOLDEN") == "1" { + if err := os.WriteFile(goldenPath, []byte(got), 0o644); err != nil { + t.Fatalf("updating golden file %s: %v", goldenPath, err) + } + return + } + want, err := os.ReadFile(goldenPath) + if err != nil { + t.Fatalf("reading golden file %s: %v", goldenPath, err) + } + if got != string(want) { + t.Errorf("output mismatch for %s:\ngot:\n%s\nwant:\n%s", goldenPath, got, string(want)) + } +} + +func TestGenerate_ExposedOperation(t *testing.T) { + const params = "openapi_ref_prefix=../openapi/openapiv3.yaml#/components/schemas/," + + "nexusrpc_out=nexus/nexusrpc.yaml," + + "nexusrpc_langs_out=nexus/nexusrpc.langs.yaml," + + "python_package_prefix=example.api," + + "typescript_package_prefix=@example/api," + + "include_operation_tags=exposed" + + files := runGenerate(t, params) + + compareGolden(t, files["nexus/nexusrpc.yaml"], "testdata/nexusrpc.yaml") + compareGolden(t, files["nexus/nexusrpc.langs.yaml"], "testdata/nexusrpc_langs.yaml") +} + +func TestGenerate_ExcludeTag_ProducesNoFiles(t *testing.T) { + const params = "nexusrpc_out=nexus/nexusrpc.yaml," + + "nexusrpc_langs_out=nexus/nexusrpc.langs.yaml," + + "exclude_operation_tags=exposed" + + files := runGenerate(t, params) + + if len(files) != 0 { + t.Errorf("expected no files when operation tag is excluded, got: %v", files) + } +} + +func TestGenerate_NoIncludeFilter_IncludesAnnotatedOperations(t *testing.T) { + // When no include_operation_tags is set, any annotated operation is included. + const params = "nexusrpc_langs_out=nexus/nexusrpc.langs.yaml" + + files := runGenerate(t, params) + + if _, ok := files["nexus/nexusrpc.langs.yaml"]; !ok { + t.Error("expected nexusrpc.langs.yaml to be generated when no include filter is set") + } +} diff --git a/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc.yaml b/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc.yaml new file mode 100644 index 000000000..7c56a479e --- /dev/null +++ b/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc.yaml @@ -0,0 +1,9 @@ +nexusrpc: 1.0.0 +services: + TestService: + operations: + DoThing: + input: + $ref: ../openapi/openapiv3.yaml#/components/schemas/DoThingRequest + output: + $ref: ../openapi/openapiv3.yaml#/components/schemas/DoThingResponse diff --git a/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc_langs.yaml b/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc_langs.yaml new file mode 100644 index 000000000..f010cfb00 --- /dev/null +++ b/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc_langs.yaml @@ -0,0 +1,19 @@ +nexusrpc: 1.0.0 +services: + TestService: + operations: + DoThing: + input: + $dotnetRef: Example.Api.Test.V1.DoThingRequest + $goRef: example.com/api/test/v1.DoThingRequest + $javaRef: com.example.api.test.v1.DoThingRequest + $pythonRef: example.api.test.v1.DoThingRequest + $rubyRef: Example::Api::Test::V1::DoThingRequest + $typescriptRef: '@example/api/test/v1.DoThingRequest' + output: + $dotnetRef: Example.Api.Test.V1.DoThingResponse + $goRef: example.com/api/test/v1.DoThingResponse + $javaRef: com.example.api.test.v1.DoThingResponse + $pythonRef: example.api.test.v1.DoThingResponse + $rubyRef: Example::Api::Test::V1::DoThingResponse + $typescriptRef: '@example/api/test/v1.DoThingResponse' diff --git a/cmd/protoc-gen-nexus-rpc-yaml/testdata/test/v1/service.proto b/cmd/protoc-gen-nexus-rpc-yaml/testdata/test/v1/service.proto new file mode 100644 index 000000000..0a37a0eb3 --- /dev/null +++ b/cmd/protoc-gen-nexus-rpc-yaml/testdata/test/v1/service.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package test.v1; + +import "nexusannotations/v1/options.proto"; + +option go_package = "example.com/api/test/v1;testv1"; +option java_package = "com.example.api.test.v1"; +option ruby_package = "Example::Api::Test::V1"; +option csharp_namespace = "Example.Api.Test.V1"; + +service TestService { + rpc DoThing(DoThingRequest) returns (DoThingResponse) { + option (nexusannotations.v1.operation) = { + tags: "exposed" + }; + } +} + +message DoThingRequest {} +message DoThingResponse {} From 1b7b2b5b751ed5fec551fb357cd6126d29e0114b Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Tue, 14 Apr 2026 12:01:58 -0600 Subject: [PATCH 14/22] proto --- buf.yaml | 1 + openapi/openapiv2.json | 224 ++++++++++++++++++++--------------------- 2 files changed, 113 insertions(+), 112 deletions(-) diff --git a/buf.yaml b/buf.yaml index 6b9d9eb57..2f2fa5389 100644 --- a/buf.yaml +++ b/buf.yaml @@ -21,3 +21,4 @@ lint: - DEFAULT ignore: - google + - cmd diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 8d4538d07..65a0ab54a 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -9332,7 +9332,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Link" + "$ref": "#/definitions/apiCommonV1Link" }, "description": "Links to be associated with the WorkflowExecutionSignaled event." } @@ -11162,7 +11162,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -11177,6 +11177,85 @@ }, "description": "Common callback information. Specific CallbackInfo messages should embed this and may include additional fields." }, + "apiCommonV1Link": { + "type": "object", + "properties": { + "workflowEvent": { + "$ref": "#/definitions/LinkWorkflowEvent" + }, + "batchJob": { + "$ref": "#/definitions/LinkBatchJob" + }, + "activity": { + "$ref": "#/definitions/LinkActivity" + } + }, + "description": "Link can be associated with history events. It might contain information about an external entity\nrelated to the history event. For example, workflow A makes a Nexus call that starts workflow B:\nin this case, a history event in workflow A could contain a Link to the workflow started event in\nworkflow B, and vice-versa." + }, + "apiFailureV1Failure": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "source": { + "type": "string", + "description": "The source this Failure originated in, e.g. TypeScriptSDK / JavaSDK\nIn some SDKs this is used to rehydrate the stack trace into an exception object." + }, + "stackTrace": { + "type": "string" + }, + "encodedAttributes": { + "$ref": "#/definitions/v1Payload", + "description": "Alternative way to supply `message` and `stack_trace` and possibly other attributes, used for encryption of\nerrors originating in user code which might contain sensitive information.\nThe `encoded_attributes` Payload could represent any serializable object, e.g. JSON object or a `Failure` proto\nmessage.\n\nSDK authors:\n- The SDK should provide a default `encodeFailureAttributes` and `decodeFailureAttributes` implementation that:\n - Uses a JSON object to represent `{ message, stack_trace }`.\n - Overwrites the original message with \"Encoded failure\" to indicate that more information could be extracted.\n - Overwrites the original stack_trace with an empty string.\n - The resulting JSON object is converted to Payload using the default PayloadConverter and should be processed\n by the user-provided PayloadCodec\n\n- If there's demand, we could allow overriding the default SDK implementation to encode other opaque Failure attributes." + }, + "cause": { + "$ref": "#/definitions/apiFailureV1Failure" + }, + "applicationFailureInfo": { + "$ref": "#/definitions/v1ApplicationFailureInfo" + }, + "timeoutFailureInfo": { + "$ref": "#/definitions/v1TimeoutFailureInfo" + }, + "canceledFailureInfo": { + "$ref": "#/definitions/v1CanceledFailureInfo" + }, + "terminatedFailureInfo": { + "$ref": "#/definitions/v1TerminatedFailureInfo" + }, + "serverFailureInfo": { + "$ref": "#/definitions/v1ServerFailureInfo" + }, + "resetWorkflowFailureInfo": { + "$ref": "#/definitions/v1ResetWorkflowFailureInfo" + }, + "activityFailureInfo": { + "$ref": "#/definitions/v1ActivityFailureInfo" + }, + "childWorkflowExecutionFailureInfo": { + "$ref": "#/definitions/v1ChildWorkflowExecutionFailureInfo" + }, + "nexusOperationExecutionFailureInfo": { + "$ref": "#/definitions/v1NexusOperationFailureInfo" + }, + "nexusHandlerFailureInfo": { + "$ref": "#/definitions/v1NexusHandlerFailureInfo" + } + } + }, + "apiUpdateV1Request": { + "type": "object", + "properties": { + "meta": { + "$ref": "#/definitions/v1Meta" + }, + "input": { + "$ref": "#/definitions/v1Input" + } + }, + "description": "The client request that triggers a Workflow Update." + }, "apiWorkflowV1CallbackInfo": { "type": "object", "properties": { @@ -11207,7 +11286,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -11344,7 +11423,7 @@ "description": "Time when the activity transitioned to a closed state." }, "lastFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "Failure details from the last failed attempt." }, "lastWorkerIdentity": { @@ -11400,7 +11479,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Link" + "$ref": "#/definitions/apiCommonV1Link" }, "description": "Links to related entities, such as the entity that started this activity." } @@ -11469,7 +11548,7 @@ "description": "The result if the activity completed successfully." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "The failure if the activity completed unsuccessfully." } }, @@ -11659,7 +11738,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "title": "Failure details" }, "scheduledEventId": { @@ -11761,7 +11840,7 @@ "title": "Starting at 1, the number of times this task has been attempted" }, "lastFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "Will be set to the most recent failure details, if this task has previously failed and then\nbeen retried." }, "workerVersion": { @@ -11779,7 +11858,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "If this activity had failed, was retried, and then timed out, that failure is stored as the\n`cause` in here." }, "scheduledEventId": { @@ -12239,7 +12318,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Link" + "$ref": "#/definitions/apiCommonV1Link" }, "description": "Links associated with the callback. It can be used to link to underlying resources of the\ncallback." } @@ -12347,7 +12426,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/apiFailureV1Failure" }, "namespace": { "type": "string", @@ -13443,58 +13522,6 @@ }, "title": "Represents a historical replication status of a Namespace" }, - "v1Failure": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "source": { - "type": "string", - "description": "The source this Failure originated in, e.g. TypeScriptSDK / JavaSDK\nIn some SDKs this is used to rehydrate the stack trace into an exception object." - }, - "stackTrace": { - "type": "string" - }, - "encodedAttributes": { - "$ref": "#/definitions/v1Payload", - "description": "Alternative way to supply `message` and `stack_trace` and possibly other attributes, used for encryption of\nerrors originating in user code which might contain sensitive information.\nThe `encoded_attributes` Payload could represent any serializable object, e.g. JSON object or a `Failure` proto\nmessage.\n\nSDK authors:\n- The SDK should provide a default `encodeFailureAttributes` and `decodeFailureAttributes` implementation that:\n - Uses a JSON object to represent `{ message, stack_trace }`.\n - Overwrites the original message with \"Encoded failure\" to indicate that more information could be extracted.\n - Overwrites the original stack_trace with an empty string.\n - The resulting JSON object is converted to Payload using the default PayloadConverter and should be processed\n by the user-provided PayloadCodec\n\n- If there's demand, we could allow overriding the default SDK implementation to encode other opaque Failure attributes." - }, - "cause": { - "$ref": "#/definitions/v1Failure" - }, - "applicationFailureInfo": { - "$ref": "#/definitions/v1ApplicationFailureInfo" - }, - "timeoutFailureInfo": { - "$ref": "#/definitions/v1TimeoutFailureInfo" - }, - "canceledFailureInfo": { - "$ref": "#/definitions/v1CanceledFailureInfo" - }, - "terminatedFailureInfo": { - "$ref": "#/definitions/v1TerminatedFailureInfo" - }, - "serverFailureInfo": { - "$ref": "#/definitions/v1ServerFailureInfo" - }, - "resetWorkflowFailureInfo": { - "$ref": "#/definitions/v1ResetWorkflowFailureInfo" - }, - "activityFailureInfo": { - "$ref": "#/definitions/v1ActivityFailureInfo" - }, - "childWorkflowExecutionFailureInfo": { - "$ref": "#/definitions/v1ChildWorkflowExecutionFailureInfo" - }, - "nexusOperationExecutionFailureInfo": { - "$ref": "#/definitions/v1NexusOperationFailureInfo" - }, - "nexusHandlerFailureInfo": { - "$ref": "#/definitions/v1NexusHandlerFailureInfo" - } - } - }, "v1FetchWorkerConfigResponse": { "type": "object", "properties": { @@ -13799,7 +13826,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Link" + "$ref": "#/definitions/apiCommonV1Link" }, "description": "Links to related entities, such as the entity that started this event's workflow." }, @@ -14061,21 +14088,6 @@ }, "description": "IntervalSpec matches times that can be expressed as:\nepoch + n * interval + phase\nwhere n is an integer.\nphase defaults to zero if missing. interval is required.\nBoth interval and phase must be non-negative and are truncated to the nearest\nsecond before any calculations.\nFor example, an interval of 1 hour with phase of zero would match every hour,\non the hour. The same interval but a phase of 19 minutes would match every\nxx:19:00. An interval of 28 days with phase zero would match\n2022-02-17T00:00:00Z (among other times). The same interval with a phase of 3\ndays, 5 hours, and 23 minutes would match 2022-02-20T05:23:00Z instead." }, - "v1Link": { - "type": "object", - "properties": { - "workflowEvent": { - "$ref": "#/definitions/LinkWorkflowEvent" - }, - "batchJob": { - "$ref": "#/definitions/LinkBatchJob" - }, - "activity": { - "$ref": "#/definitions/LinkActivity" - } - }, - "description": "Link can be associated with history events. It might contain information about an external entity\nrelated to the history event. For example, workflow A makes a Nexus call that starts workflow B:\nin this case, a history event in workflow A could contain a Link to the workflow started event in\nworkflow B, and vice-versa." - }, "v1ListActivityExecutionsResponse": { "type": "object", "properties": { @@ -14328,7 +14340,7 @@ "$ref": "#/definitions/v1Header" }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "Some uses of markers, like a local activity, could \"fail\". If they did that is recorded here." } } @@ -14666,7 +14678,7 @@ "description": "The `WORKFLOW_TASK_COMPLETED` event that the corresponding RequestCancelNexusOperation command was reported\nwith." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping a CanceledFailureInfo." }, "scheduledEventId": { @@ -14700,7 +14712,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "Cancellation details." }, "requestId": { @@ -14732,7 +14744,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -14789,7 +14801,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping an ApplicationFailureInfo." }, "requestId": { @@ -14916,7 +14928,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping a CanceledFailureInfo." }, "requestId": { @@ -14951,7 +14963,7 @@ "$ref": "#/definitions/v1Payloads" }, "failure": { - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/apiFailureV1Failure" } }, "description": "The outcome of a Workflow Update: success or failure." @@ -15034,7 +15046,7 @@ "format": "date-time" }, "lastFailure": { - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/apiFailureV1Failure" }, "lastWorkerIdentity": { "type": "string" @@ -15172,7 +15184,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -15653,18 +15665,6 @@ ], "default": "REPLICATION_STATE_UNSPECIFIED" }, - "v1Request": { - "type": "object", - "properties": { - "meta": { - "$ref": "#/definitions/v1Meta" - }, - "input": { - "$ref": "#/definitions/v1Input" - } - }, - "description": "The client request that triggers a Workflow Update." - }, "v1RequestCancelActivityExecutionResponse": { "type": "object" }, @@ -15913,7 +15913,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/apiFailureV1Failure" }, "title": "Server validation failures could include\nlast_heartbeat_details payload is too large, request failure is too large" } @@ -15926,7 +15926,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/apiFailureV1Failure" }, "title": "Server validation failures could include\nlast_heartbeat_details payload is too large, request failure is too large" } @@ -16564,7 +16564,7 @@ "description": "If true, a new activity was started." }, "link": { - "$ref": "#/definitions/v1Link", + "$ref": "#/definitions/apiCommonV1Link", "description": "Link to the started activity." } } @@ -16713,7 +16713,7 @@ "description": "When `request_eager_execution` is set on the `StartWorkflowExecutionRequest`, the server - if supported - will\nreturn the first workflow task to be eagerly executed.\nThe caller is expected to have a worker available to process the task." }, "link": { - "$ref": "#/definitions/v1Link", + "$ref": "#/definitions/apiCommonV1Link", "description": "Link to the workflow event." } } @@ -18158,7 +18158,7 @@ "$ref": "#/definitions/v1ContinueAsNewInitiator" }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "Deprecated. If a workflow's retry policy would cause a new run to start when the current one\nhas failed, this field would be populated with that failure. Now (when supported by server\nand sdk) the final event will be `WORKFLOW_EXECUTION_FAILED` with `new_execution_run_id` set." }, "lastCompletionResult": { @@ -18233,7 +18233,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "title": "Serialized result of workflow failure (ex: An exception thrown, or error returned)" }, "retryState": { @@ -18522,7 +18522,7 @@ "$ref": "#/definitions/v1ContinueAsNewInitiator" }, "continuedFailure": { - "$ref": "#/definitions/v1Failure" + "$ref": "#/definitions/apiFailureV1Failure" }, "lastCompletionResult": { "$ref": "#/definitions/v1Payloads" @@ -18735,7 +18735,7 @@ "description": "The event ID used to sequence the original request message." }, "acceptedRequest": { - "$ref": "#/definitions/v1Request", + "$ref": "#/definitions/apiUpdateV1Request", "description": "The message payload of the original request message that initiated this\nupdate." } } @@ -18744,7 +18744,7 @@ "type": "object", "properties": { "request": { - "$ref": "#/definitions/v1Request", + "$ref": "#/definitions/apiUpdateV1Request", "description": "The update request associated with this event." }, "origin": { @@ -18788,11 +18788,11 @@ "description": "The event ID used to sequence the original request message." }, "rejectedRequest": { - "$ref": "#/definitions/v1Request", + "$ref": "#/definitions/apiUpdateV1Request", "description": "The message payload of the original request message that initiated this\nupdate." }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "description": "The cause of rejection." } } @@ -19128,7 +19128,7 @@ "$ref": "#/definitions/v1WorkflowTaskFailedCause" }, "failure": { - "$ref": "#/definitions/v1Failure", + "$ref": "#/definitions/apiFailureV1Failure", "title": "The failure details" }, "identity": { From e9a0f6c61739e6bfa8decaf941e4b71d491ddc33 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Thu, 16 Apr 2026 11:30:45 -0600 Subject: [PATCH 15/22] ci-build --- openapi/openapiv2.json | 228 ++++++++++++++++++++--------------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 788bea7c6..02e2d1436 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -9332,7 +9332,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/apiCommonV1Link" + "$ref": "#/definitions/v1Link" }, "description": "Links to be associated with the WorkflowExecutionSignaled event." } @@ -11166,7 +11166,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -11181,21 +11181,6 @@ }, "description": "Common callback information. Specific CallbackInfo messages should embed this and may include additional fields." }, - "apiCommonV1Link": { - "type": "object", - "properties": { - "workflowEvent": { - "$ref": "#/definitions/LinkWorkflowEvent" - }, - "batchJob": { - "$ref": "#/definitions/LinkBatchJob" - }, - "activity": { - "$ref": "#/definitions/LinkActivity" - } - }, - "description": "Link can be associated with history events. It might contain information about an external entity\nrelated to the history event. For example, workflow A makes a Nexus call that starts workflow B:\nin this case, a history event in workflow A could contain a Link to the workflow started event in\nworkflow B, and vice-versa." - }, "apiCommonV1OnConflictOptions": { "type": "object", "properties": { @@ -11214,70 +11199,6 @@ }, "description": "When starting an execution with a conflict policy that uses an existing execution and there is already an existing\nrunning execution, OnConflictOptions defines actions to be taken on the existing running execution." }, - "apiFailureV1Failure": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "source": { - "type": "string", - "description": "The source this Failure originated in, e.g. TypeScriptSDK / JavaSDK\nIn some SDKs this is used to rehydrate the stack trace into an exception object." - }, - "stackTrace": { - "type": "string" - }, - "encodedAttributes": { - "$ref": "#/definitions/v1Payload", - "description": "Alternative way to supply `message` and `stack_trace` and possibly other attributes, used for encryption of\nerrors originating in user code which might contain sensitive information.\nThe `encoded_attributes` Payload could represent any serializable object, e.g. JSON object or a `Failure` proto\nmessage.\n\nSDK authors:\n- The SDK should provide a default `encodeFailureAttributes` and `decodeFailureAttributes` implementation that:\n - Uses a JSON object to represent `{ message, stack_trace }`.\n - Overwrites the original message with \"Encoded failure\" to indicate that more information could be extracted.\n - Overwrites the original stack_trace with an empty string.\n - The resulting JSON object is converted to Payload using the default PayloadConverter and should be processed\n by the user-provided PayloadCodec\n\n- If there's demand, we could allow overriding the default SDK implementation to encode other opaque Failure attributes." - }, - "cause": { - "$ref": "#/definitions/apiFailureV1Failure" - }, - "applicationFailureInfo": { - "$ref": "#/definitions/v1ApplicationFailureInfo" - }, - "timeoutFailureInfo": { - "$ref": "#/definitions/v1TimeoutFailureInfo" - }, - "canceledFailureInfo": { - "$ref": "#/definitions/v1CanceledFailureInfo" - }, - "terminatedFailureInfo": { - "$ref": "#/definitions/v1TerminatedFailureInfo" - }, - "serverFailureInfo": { - "$ref": "#/definitions/v1ServerFailureInfo" - }, - "resetWorkflowFailureInfo": { - "$ref": "#/definitions/v1ResetWorkflowFailureInfo" - }, - "activityFailureInfo": { - "$ref": "#/definitions/v1ActivityFailureInfo" - }, - "childWorkflowExecutionFailureInfo": { - "$ref": "#/definitions/v1ChildWorkflowExecutionFailureInfo" - }, - "nexusOperationExecutionFailureInfo": { - "$ref": "#/definitions/v1NexusOperationFailureInfo" - }, - "nexusHandlerFailureInfo": { - "$ref": "#/definitions/v1NexusHandlerFailureInfo" - } - } - }, - "apiUpdateV1Request": { - "type": "object", - "properties": { - "meta": { - "$ref": "#/definitions/v1Meta" - }, - "input": { - "$ref": "#/definitions/v1Input" - } - }, - "description": "The client request that triggers a Workflow Update." - }, "apiWorkflowV1CallbackInfo": { "type": "object", "properties": { @@ -11308,7 +11229,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -11463,7 +11384,7 @@ "description": "Time when the activity transitioned to a closed state." }, "lastFailure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "Failure details from the last failed attempt." }, "lastWorkerIdentity": { @@ -11519,7 +11440,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/apiCommonV1Link" + "$ref": "#/definitions/v1Link" }, "description": "Links to related entities, such as the entity that started this activity." } @@ -11588,7 +11509,7 @@ "description": "The result if the activity completed successfully." }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "The failure if the activity completed unsuccessfully." } }, @@ -11778,7 +11699,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "title": "Failure details" }, "scheduledEventId": { @@ -11880,7 +11801,7 @@ "title": "Starting at 1, the number of times this task has been attempted" }, "lastFailure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "Will be set to the most recent failure details, if this task has previously failed and then\nbeen retried." }, "workerVersion": { @@ -11898,7 +11819,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "If this activity had failed, was retried, and then timed out, that failure is stored as the\n`cause` in here." }, "scheduledEventId": { @@ -12358,7 +12279,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/apiCommonV1Link" + "$ref": "#/definitions/v1Link" }, "description": "Links associated with the callback. It can be used to link to underlying resources of the\ncallback." } @@ -12466,7 +12387,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/apiFailureV1Failure" + "$ref": "#/definitions/v1Failure" }, "namespace": { "type": "string", @@ -13562,6 +13483,58 @@ }, "title": "Represents a historical replication status of a Namespace" }, + "v1Failure": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "source": { + "type": "string", + "description": "The source this Failure originated in, e.g. TypeScriptSDK / JavaSDK\nIn some SDKs this is used to rehydrate the stack trace into an exception object." + }, + "stackTrace": { + "type": "string" + }, + "encodedAttributes": { + "$ref": "#/definitions/v1Payload", + "description": "Alternative way to supply `message` and `stack_trace` and possibly other attributes, used for encryption of\nerrors originating in user code which might contain sensitive information.\nThe `encoded_attributes` Payload could represent any serializable object, e.g. JSON object or a `Failure` proto\nmessage.\n\nSDK authors:\n- The SDK should provide a default `encodeFailureAttributes` and `decodeFailureAttributes` implementation that:\n - Uses a JSON object to represent `{ message, stack_trace }`.\n - Overwrites the original message with \"Encoded failure\" to indicate that more information could be extracted.\n - Overwrites the original stack_trace with an empty string.\n - The resulting JSON object is converted to Payload using the default PayloadConverter and should be processed\n by the user-provided PayloadCodec\n\n- If there's demand, we could allow overriding the default SDK implementation to encode other opaque Failure attributes." + }, + "cause": { + "$ref": "#/definitions/v1Failure" + }, + "applicationFailureInfo": { + "$ref": "#/definitions/v1ApplicationFailureInfo" + }, + "timeoutFailureInfo": { + "$ref": "#/definitions/v1TimeoutFailureInfo" + }, + "canceledFailureInfo": { + "$ref": "#/definitions/v1CanceledFailureInfo" + }, + "terminatedFailureInfo": { + "$ref": "#/definitions/v1TerminatedFailureInfo" + }, + "serverFailureInfo": { + "$ref": "#/definitions/v1ServerFailureInfo" + }, + "resetWorkflowFailureInfo": { + "$ref": "#/definitions/v1ResetWorkflowFailureInfo" + }, + "activityFailureInfo": { + "$ref": "#/definitions/v1ActivityFailureInfo" + }, + "childWorkflowExecutionFailureInfo": { + "$ref": "#/definitions/v1ChildWorkflowExecutionFailureInfo" + }, + "nexusOperationExecutionFailureInfo": { + "$ref": "#/definitions/v1NexusOperationFailureInfo" + }, + "nexusHandlerFailureInfo": { + "$ref": "#/definitions/v1NexusHandlerFailureInfo" + } + } + }, "v1FetchWorkerConfigResponse": { "type": "object", "properties": { @@ -13866,7 +13839,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/apiCommonV1Link" + "$ref": "#/definitions/v1Link" }, "description": "Links to related entities, such as the entity that started this event's workflow." }, @@ -14128,6 +14101,21 @@ }, "description": "IntervalSpec matches times that can be expressed as:\nepoch + n * interval + phase\nwhere n is an integer.\nphase defaults to zero if missing. interval is required.\nBoth interval and phase must be non-negative and are truncated to the nearest\nsecond before any calculations.\nFor example, an interval of 1 hour with phase of zero would match every hour,\non the hour. The same interval but a phase of 19 minutes would match every\nxx:19:00. An interval of 28 days with phase zero would match\n2022-02-17T00:00:00Z (among other times). The same interval with a phase of 3\ndays, 5 hours, and 23 minutes would match 2022-02-20T05:23:00Z instead." }, + "v1Link": { + "type": "object", + "properties": { + "workflowEvent": { + "$ref": "#/definitions/LinkWorkflowEvent" + }, + "batchJob": { + "$ref": "#/definitions/LinkBatchJob" + }, + "activity": { + "$ref": "#/definitions/LinkActivity" + } + }, + "description": "Link can be associated with history events. It might contain information about an external entity\nrelated to the history event. For example, workflow A makes a Nexus call that starts workflow B:\nin this case, a history event in workflow A could contain a Link to the workflow started event in\nworkflow B, and vice-versa." + }, "v1ListActivityExecutionsResponse": { "type": "object", "properties": { @@ -14380,7 +14368,7 @@ "$ref": "#/definitions/v1Header" }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "Some uses of markers, like a local activity, could \"fail\". If they did that is recorded here." } } @@ -14718,7 +14706,7 @@ "description": "The `WORKFLOW_TASK_COMPLETED` event that the corresponding RequestCancelNexusOperation command was reported\nwith." }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping a CanceledFailureInfo." }, "scheduledEventId": { @@ -14752,7 +14740,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "Cancellation details." }, "requestId": { @@ -14784,7 +14772,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -14841,7 +14829,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping an ApplicationFailureInfo." }, "requestId": { @@ -14968,7 +14956,7 @@ "description": "The ID of the `NEXUS_OPERATION_SCHEDULED` event. Uniquely identifies this operation." }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "Failure details. A NexusOperationFailureInfo wrapping a CanceledFailureInfo." }, "requestId": { @@ -14985,7 +14973,7 @@ "$ref": "#/definitions/v1Payloads" }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure" + "$ref": "#/definitions/v1Failure" } }, "description": "The outcome of a Workflow Update: success or failure." @@ -15068,7 +15056,7 @@ "format": "date-time" }, "lastFailure": { - "$ref": "#/definitions/apiFailureV1Failure" + "$ref": "#/definitions/v1Failure" }, "lastWorkerIdentity": { "type": "string" @@ -15206,7 +15194,7 @@ "description": "The time when the last attempt completed." }, "lastAttemptFailure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "The last attempt's failure, if any." }, "nextAttemptScheduleTime": { @@ -15687,6 +15675,18 @@ ], "default": "REPLICATION_STATE_UNSPECIFIED" }, + "v1Request": { + "type": "object", + "properties": { + "meta": { + "$ref": "#/definitions/v1Meta" + }, + "input": { + "$ref": "#/definitions/v1Input" + } + }, + "description": "The client request that triggers a Workflow Update." + }, "v1RequestCancelActivityExecutionResponse": { "type": "object" }, @@ -15935,7 +15935,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/apiFailureV1Failure" + "$ref": "#/definitions/v1Failure" }, "title": "Server validation failures could include\nlast_heartbeat_details payload is too large, request failure is too large" } @@ -15948,7 +15948,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/apiFailureV1Failure" + "$ref": "#/definitions/v1Failure" }, "title": "Server validation failures could include\nlast_heartbeat_details payload is too large, request failure is too large" } @@ -16570,7 +16570,7 @@ "description": "If true, a new workflow was started." }, "signalLink": { - "$ref": "#/definitions/apiCommonV1Link", + "$ref": "#/definitions/v1Link", "description": "Link to be associated with the WorkflowExecutionSignaled event.\nAdded on the response to propagate the backlink.\nAvailable from Temporal server 1.31 and up." } } @@ -16579,7 +16579,7 @@ "type": "object", "properties": { "link": { - "$ref": "#/definitions/apiCommonV1Link", + "$ref": "#/definitions/v1Link", "description": "Link to be associated with the WorkflowExecutionSignaled event.\nAdded on the response to propagate the backlink.\nAvailable from Temporal server 1.31 and up." } } @@ -16596,7 +16596,7 @@ "description": "If true, a new activity was started." }, "link": { - "$ref": "#/definitions/apiCommonV1Link", + "$ref": "#/definitions/v1Link", "description": "Link to the started activity." } } @@ -16745,7 +16745,7 @@ "description": "When `request_eager_execution` is set on the `StartWorkflowExecutionRequest`, the server - if supported - will\nreturn the first workflow task to be eagerly executed.\nThe caller is expected to have a worker available to process the task." }, "link": { - "$ref": "#/definitions/apiCommonV1Link", + "$ref": "#/definitions/v1Link", "description": "Link to the workflow event." } } @@ -18190,7 +18190,7 @@ "$ref": "#/definitions/v1ContinueAsNewInitiator" }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "Deprecated. If a workflow's retry policy would cause a new run to start when the current one\nhas failed, this field would be populated with that failure. Now (when supported by server\nand sdk) the final event will be `WORKFLOW_EXECUTION_FAILED` with `new_execution_run_id` set." }, "lastCompletionResult": { @@ -18265,7 +18265,7 @@ "type": "object", "properties": { "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "title": "Serialized result of workflow failure (ex: An exception thrown, or error returned)" }, "retryState": { @@ -18558,7 +18558,7 @@ "$ref": "#/definitions/v1ContinueAsNewInitiator" }, "continuedFailure": { - "$ref": "#/definitions/apiFailureV1Failure" + "$ref": "#/definitions/v1Failure" }, "lastCompletionResult": { "$ref": "#/definitions/v1Payloads" @@ -18771,7 +18771,7 @@ "description": "The event ID used to sequence the original request message." }, "acceptedRequest": { - "$ref": "#/definitions/apiUpdateV1Request", + "$ref": "#/definitions/v1Request", "description": "The message payload of the original request message that initiated this\nupdate." } } @@ -18780,7 +18780,7 @@ "type": "object", "properties": { "request": { - "$ref": "#/definitions/apiUpdateV1Request", + "$ref": "#/definitions/v1Request", "description": "The update request associated with this event." }, "origin": { @@ -18824,11 +18824,11 @@ "description": "The event ID used to sequence the original request message." }, "rejectedRequest": { - "$ref": "#/definitions/apiUpdateV1Request", + "$ref": "#/definitions/v1Request", "description": "The message payload of the original request message that initiated this\nupdate." }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "description": "The cause of rejection." } } @@ -19164,7 +19164,7 @@ "$ref": "#/definitions/v1WorkflowTaskFailedCause" }, "failure": { - "$ref": "#/definitions/apiFailureV1Failure", + "$ref": "#/definitions/v1Failure", "title": "The failure details" }, "identity": { From e150e4157d3c66130a57a786385254d6ea847fd7 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Thu, 16 Apr 2026 11:36:57 -0600 Subject: [PATCH 16/22] remove test files --- .../generator_test.go | 162 ------------------ .../testdata/nexusrpc.yaml | 9 - .../testdata/nexusrpc_langs.yaml | 19 -- .../testdata/test/v1/service.proto | 21 --- 4 files changed, 211 deletions(-) delete mode 100644 cmd/protoc-gen-nexus-rpc-yaml/generator_test.go delete mode 100644 cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc.yaml delete mode 100644 cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc_langs.yaml delete mode 100644 cmd/protoc-gen-nexus-rpc-yaml/testdata/test/v1/service.proto diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator_test.go b/cmd/protoc-gen-nexus-rpc-yaml/generator_test.go deleted file mode 100644 index 78d7374f1..000000000 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator_test.go +++ /dev/null @@ -1,162 +0,0 @@ -package main - -import ( - "context" - "os" - "testing" - - "github.com/bufbuild/protocompile" - nexusannotationsv1 "github.com/nexus-rpc/nexus-proto-annotations/go/nexusannotations/v1" - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protodesc" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" - "google.golang.org/protobuf/types/descriptorpb" - "google.golang.org/protobuf/types/pluginpb" -) - -// runGenerate compiles testdata/test/v1/service.proto using the given plugin -// parameter string and returns the generated file contents keyed by filename. -// -// Known dependencies (google/protobuf/descriptor.proto and -// nexusannotations/v1/options.proto) are supplied as pre-compiled Go -// descriptors so that extension values are deserialized into Go-generated -// types rather than *dynamicpb.Message. -func runGenerate(t *testing.T, parameter string) map[string]string { - t.Helper() - - resolver := protocompile.CompositeResolver{ - // Return pre-compiled Go file descriptors for known dependencies. - // This ensures that the nexus extension is deserialised into the - // Go-generated *nexusannotationsv1.OperationOptions type, not a - // dynamic protobuf message, which would cause a type-assertion panic - // in shouldIncludeOperation. - protocompile.ResolverFunc(func(path string) (protocompile.SearchResult, error) { - switch path { - case "google/protobuf/descriptor.proto": - return protocompile.SearchResult{Desc: descriptorpb.File_google_protobuf_descriptor_proto}, nil - case "nexusannotations/v1/options.proto": - return protocompile.SearchResult{Desc: nexusannotationsv1.File_nexusannotations_v1_options_proto}, nil - } - return protocompile.SearchResult{}, protoregistry.NotFound - }), - // Fall back to reading source files from the testdata directory. - &protocompile.SourceResolver{ImportPaths: []string{"testdata"}}, - } - - compiledFiles, err := (&protocompile.Compiler{Resolver: resolver}).Compile( - context.Background(), "test/v1/service.proto", - ) - if err != nil { - t.Fatalf("compiling test proto: %v", err) - } - - // Collect all file descriptor protos in topological order (imports before importers). - // Each FileDescriptorProto is round-tripped through proto.Marshal + proto.Unmarshal - // to normalize extension fields. protocompile stores extension values as - // *dynamicpb.Message objects; the round-trip serializes them to raw bytes and lets - // proto.Unmarshal deserialize them as the registered Go-generated types (e.g. - // *nexusannotationsv1.OperationOptions). Without this, proto.GetExtension in the - // generator would panic with "invalid type: got *dynamicpb.Message". - seen := make(map[string]bool) - var protoFiles []*descriptorpb.FileDescriptorProto - var collect func(f protoreflect.FileDescriptor) - collect = func(f protoreflect.FileDescriptor) { - if seen[f.Path()] { - return - } - seen[f.Path()] = true - for i := 0; i < f.Imports().Len(); i++ { - collect(f.Imports().Get(i)) - } - raw, err := proto.Marshal(protodesc.ToFileDescriptorProto(f)) - if err != nil { - t.Fatalf("marshaling file descriptor %s: %v", f.Path(), err) - } - var fdp descriptorpb.FileDescriptorProto - if err := proto.Unmarshal(raw, &fdp); err != nil { - t.Fatalf("unmarshaling file descriptor %s: %v", f.Path(), err) - } - protoFiles = append(protoFiles, &fdp) - } - for _, f := range compiledFiles { - collect(f) - } - - req := &pluginpb.CodeGeneratorRequest{ - FileToGenerate: []string{"test/v1/service.proto"}, - ProtoFile: protoFiles, - Parameter: proto.String(parameter), - } - gen, err := protogen.Options{}.New(req) - if err != nil { - t.Fatalf("creating plugin: %v", err) - } - if err := generate(gen); err != nil { - t.Fatalf("generate: %v", err) - } - - result := make(map[string]string) - for _, f := range gen.Response().File { - result[f.GetName()] = f.GetContent() - } - return result -} - -// compareGolden compares got against the contents of goldenPath. -// Set UPDATE_GOLDEN=1 to overwrite the golden file with the current output -// instead of comparing, making it easy to refresh after intentional generator changes. -func compareGolden(t *testing.T, got, goldenPath string) { - t.Helper() - if os.Getenv("UPDATE_GOLDEN") == "1" { - if err := os.WriteFile(goldenPath, []byte(got), 0o644); err != nil { - t.Fatalf("updating golden file %s: %v", goldenPath, err) - } - return - } - want, err := os.ReadFile(goldenPath) - if err != nil { - t.Fatalf("reading golden file %s: %v", goldenPath, err) - } - if got != string(want) { - t.Errorf("output mismatch for %s:\ngot:\n%s\nwant:\n%s", goldenPath, got, string(want)) - } -} - -func TestGenerate_ExposedOperation(t *testing.T) { - const params = "openapi_ref_prefix=../openapi/openapiv3.yaml#/components/schemas/," + - "nexusrpc_out=nexus/nexusrpc.yaml," + - "nexusrpc_langs_out=nexus/nexusrpc.langs.yaml," + - "python_package_prefix=example.api," + - "typescript_package_prefix=@example/api," + - "include_operation_tags=exposed" - - files := runGenerate(t, params) - - compareGolden(t, files["nexus/nexusrpc.yaml"], "testdata/nexusrpc.yaml") - compareGolden(t, files["nexus/nexusrpc.langs.yaml"], "testdata/nexusrpc_langs.yaml") -} - -func TestGenerate_ExcludeTag_ProducesNoFiles(t *testing.T) { - const params = "nexusrpc_out=nexus/nexusrpc.yaml," + - "nexusrpc_langs_out=nexus/nexusrpc.langs.yaml," + - "exclude_operation_tags=exposed" - - files := runGenerate(t, params) - - if len(files) != 0 { - t.Errorf("expected no files when operation tag is excluded, got: %v", files) - } -} - -func TestGenerate_NoIncludeFilter_IncludesAnnotatedOperations(t *testing.T) { - // When no include_operation_tags is set, any annotated operation is included. - const params = "nexusrpc_langs_out=nexus/nexusrpc.langs.yaml" - - files := runGenerate(t, params) - - if _, ok := files["nexus/nexusrpc.langs.yaml"]; !ok { - t.Error("expected nexusrpc.langs.yaml to be generated when no include filter is set") - } -} diff --git a/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc.yaml b/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc.yaml deleted file mode 100644 index 7c56a479e..000000000 --- a/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc.yaml +++ /dev/null @@ -1,9 +0,0 @@ -nexusrpc: 1.0.0 -services: - TestService: - operations: - DoThing: - input: - $ref: ../openapi/openapiv3.yaml#/components/schemas/DoThingRequest - output: - $ref: ../openapi/openapiv3.yaml#/components/schemas/DoThingResponse diff --git a/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc_langs.yaml b/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc_langs.yaml deleted file mode 100644 index f010cfb00..000000000 --- a/cmd/protoc-gen-nexus-rpc-yaml/testdata/nexusrpc_langs.yaml +++ /dev/null @@ -1,19 +0,0 @@ -nexusrpc: 1.0.0 -services: - TestService: - operations: - DoThing: - input: - $dotnetRef: Example.Api.Test.V1.DoThingRequest - $goRef: example.com/api/test/v1.DoThingRequest - $javaRef: com.example.api.test.v1.DoThingRequest - $pythonRef: example.api.test.v1.DoThingRequest - $rubyRef: Example::Api::Test::V1::DoThingRequest - $typescriptRef: '@example/api/test/v1.DoThingRequest' - output: - $dotnetRef: Example.Api.Test.V1.DoThingResponse - $goRef: example.com/api/test/v1.DoThingResponse - $javaRef: com.example.api.test.v1.DoThingResponse - $pythonRef: example.api.test.v1.DoThingResponse - $rubyRef: Example::Api::Test::V1::DoThingResponse - $typescriptRef: '@example/api/test/v1.DoThingResponse' diff --git a/cmd/protoc-gen-nexus-rpc-yaml/testdata/test/v1/service.proto b/cmd/protoc-gen-nexus-rpc-yaml/testdata/test/v1/service.proto deleted file mode 100644 index 0a37a0eb3..000000000 --- a/cmd/protoc-gen-nexus-rpc-yaml/testdata/test/v1/service.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; - -package test.v1; - -import "nexusannotations/v1/options.proto"; - -option go_package = "example.com/api/test/v1;testv1"; -option java_package = "com.example.api.test.v1"; -option ruby_package = "Example::Api::Test::V1"; -option csharp_namespace = "Example.Api.Test.V1"; - -service TestService { - rpc DoThing(DoThingRequest) returns (DoThingResponse) { - option (nexusannotations.v1.operation) = { - tags: "exposed" - }; - } -} - -message DoThingRequest {} -message DoThingResponse {} From 5ab04f0ea4ec4e13011043f5eccd14c00ce7b5ed Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Thu, 16 Apr 2026 11:40:04 -0600 Subject: [PATCH 17/22] remove test deps --- cmd/protoc-gen-nexus-rpc-yaml/go.mod | 7 ++----- cmd/protoc-gen-nexus-rpc-yaml/go.sum | 10 ---------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/cmd/protoc-gen-nexus-rpc-yaml/go.mod b/cmd/protoc-gen-nexus-rpc-yaml/go.mod index c507d8486..863c771a6 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/go.mod +++ b/cmd/protoc-gen-nexus-rpc-yaml/go.mod @@ -7,9 +7,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) -require ( - github.com/bufbuild/protocompile v0.14.1 - github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 -) +require github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 -require golang.org/x/sync v0.8.0 // indirect +require github.com/google/go-cmp v0.6.0 // indirect diff --git a/cmd/protoc-gen-nexus-rpc-yaml/go.sum b/cmd/protoc-gen-nexus-rpc-yaml/go.sum index c248e2ac6..cbc5252ff 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/go.sum +++ b/cmd/protoc-gen-nexus-rpc-yaml/go.sum @@ -1,17 +1,7 @@ -github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= -github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 h1:SWHt3Coj0VvF0Km1A0wlY+IjnHKsjQLgO29io84r3wY= github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84/go.mod h1:n3UjF1bPCW8llR8tHvbxJ+27yPWrhpo8w/Yg1IOuY0Y= -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/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 4131b9010f0b432a47e9b9b651ea5771b0467043 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Fri, 17 Apr 2026 14:00:59 -0400 Subject: [PATCH 18/22] generate types into #/components/schemas directly in nexus json schema models file --- Makefile | 27 +- cmd/protoc-gen-nexus-rpc-yaml/generator.go | 317 ++++++++++++- cmd/protoc-gen-nexus-rpc-yaml/main.go | 4 +- .../temporal-json-schema-models-nexusrpc.yaml | 429 +++++++++++++++++- 4 files changed, 739 insertions(+), 38 deletions(-) diff --git a/Makefile b/Makefile index e069f75fd..e88f9fca5 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ ci-build: install proto http-api-docs install: grpc-install api-linter-install buf-install # Run all linters and compile proto files. -proto: sync-nexus-annotations grpc http-api-docs nexusrpc-yaml +proto: sync-nexus-annotations grpc http-api-docs nexus-rpc-yaml ######################################################################## ##### Variables ###### @@ -121,27 +121,22 @@ buf-breaking: @printf $(COLOR) "Run buf breaking changes check against master branch..." @(cd $(PROTO_ROOT) && buf breaking --against 'https://github.com/temporalio/api.git#branch=master') -nexusrpc-yaml: nexusrpc-yaml-install +nexus-rpc-yaml: nexus-rpc-yaml-install printf $(COLOR) "Generate nexus/temporal-json-schema-models-nexusrpc.yaml and nexus/temporal-proto-models-nexusrpc.yaml..." mkdir -p nexus protoc -I $(PROTO_ROOT) \ - --nexusrpc_opt=openapi_ref_prefix=../openapi/openapiv3.yaml#/components/schemas/ \ - --nexusrpc_opt=nexusrpc_out=nexus/temporal-json-schema-models-nexusrpc.yaml \ - --nexusrpc_opt=nexusrpc_langs_out=nexus/temporal-proto-models-nexusrpc.yaml \ - --nexusrpc_opt=python_package_prefix=temporalio.api \ - --nexusrpc_opt=typescript_package_prefix=@temporalio/api \ - --nexusrpc_opt=include_operation_tags=exposed \ - --nexusrpc_out=. \ + --nexus-rpc-yaml_opt=nexus-rpc_out=nexus/temporal-json-schema-models-nexusrpc.yaml \ + --nexus-rpc-yaml_opt=nexus-rpc_langs_out=nexus/temporal-proto-models-nexusrpc.yaml \ + --nexus-rpc-yaml_opt=python_package_prefix=temporalio.api \ + --nexus-rpc-yaml_opt=typescript_package_prefix=@temporalio/api \ + --nexus-rpc-yaml_opt=include_operation_tags=exposed \ + --nexus-rpc-yaml_out=. \ temporal/api/workflowservice/v1/* \ temporal/api/operatorservice/v1/* -nexusrpc-yaml-install: - # TODO seankane: after merging nexus-rpc/nexus-rpc-gen#36 update this to install from `main` instead of branch - printf $(COLOR) "Install protoc-gen-nexusrpc from nexus-rpc/nexus-rpc-gen@spk/protoc-plugin..." - @NEXUSRPC_TMP=$$(mktemp -d) && \ - git clone --quiet --depth=1 --branch=spk/protoc-plugin https://github.com/nexus-rpc/nexus-rpc-gen.git $$NEXUSRPC_TMP && \ - cd $$NEXUSRPC_TMP/tools/protoc-gen-nexusrpc && go install ./cmd/protoc-gen-nexusrpc && \ - rm -rf $$NEXUSRPC_TMP +nexus-rpc-yaml-install: + printf $(COLOR) "Build and install protoc-gen-nexus-rpc-yaml..." + @cd cmd/protoc-gen-nexus-rpc-yaml && go install . ##### Clean ##### clean: diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go index 9d2ecb5ca..1643b8060 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -17,17 +17,17 @@ import ( // params holds the parsed protoc plugin options. // Passed via --nexus-rpc-yaml_opt=key=value (multiple opts are comma-joined by protoc). // -// - openapi_ref_prefix: optional. Prefix prepended to the message name to form the -// JSON Schema $ref in nexusrpc.yaml. If empty, nexusrpc.yaml is not written. +// - openapi_ref_prefix: optional. When set, nexus-rpc_out emits a bare $ref to the OpenAPI +// schema rather than inlining schemas under components/schemas. // Example: "../openapi/openapiv3.yaml#/components/schemas/" // -// - nexusrpc_out: optional. Output path for nexusrpc.yaml (relative to --nexus-rpc-yaml_out dir). -// If empty, nexusrpc.yaml is not written. Requires openapi_ref_prefix to also be set. -// Example: "nexus/nexusrpc.yaml" +// - nexus-rpc_out: optional. Output path for nexus-rpc.yaml (relative to --nexus-rpc-yaml_out dir). +// If empty, nexus-rpc.yaml is not written. +// Example: "nexus/nexus-rpc.yaml" // -// - nexusrpc_langs_out: optional. Output path for nexusrpc.langs.yaml. -// If empty, nexusrpc.langs.yaml is not written. -// Example: "nexus/nexusrpc.langs.yaml" +// - nexus-rpc_langs_out: optional. Output path for nexus-rpc.langs.yaml. +// If empty, nexus-rpc.langs.yaml is not written. +// Example: "nexus/nexus-rpc.langs.yaml" // // - python_package_prefix: optional. Dot-separated package prefix for $pythonRef. // The last two path segments of the go_package ({service}/v{n}) are appended. @@ -49,8 +49,8 @@ import ( // Example: exclude_operation_tags=internal type params struct { openAPIRefPrefix string - nexusrpcOut string - nexusrpcLangsOut string + nexusRpcOut string + nexusRpcLangsOut string pythonPackagePrefix string typescriptPackagePrefix string includeOperationTags []string @@ -71,10 +71,10 @@ func parseParams(raw string) (params, error) { switch key { case "openapi_ref_prefix": p.openAPIRefPrefix = value - case "nexusrpc_out": - p.nexusrpcOut = value - case "nexusrpc_langs_out": - p.nexusrpcLangsOut = value + case "nexus-rpc_out": + p.nexusRpcOut = value + case "nexus-rpc_langs_out": + p.nexusRpcLangsOut = value case "python_package_prefix": p.pythonPackagePrefix = value case "typescript_package_prefix": @@ -123,6 +123,7 @@ func generate(gen *protogen.Plugin) error { nexusDoc := newDoc() langsDoc := newDoc() hasOps := false + collector := newSchemaCollector() for _, f := range gen.Files { if !f.Generate { @@ -143,6 +144,15 @@ func generate(gen *protogen.Plugin) error { map[string]string{"$ref": p.openAPIRefPrefix + string(m.Input.Desc.Name())}, map[string]string{"$ref": p.openAPIRefPrefix + string(m.Output.Desc.Name())}, ) + } else { + inputName := msgSchemaName(m.Input.Desc) + outputName := msgSchemaName(m.Output.Desc) + collector.collect(m.Input.Desc) + collector.collect(m.Output.Desc) + addOperation(nexusDoc, svcName, methodName, + map[string]string{"$ref": "#/components/schemas/" + inputName}, + map[string]string{"$ref": "#/components/schemas/" + outputName}, + ) } addOperation(langsDoc, svcName, methodName, @@ -157,13 +167,17 @@ func generate(gen *protogen.Plugin) error { return nil } - if p.openAPIRefPrefix != "" && p.nexusrpcOut != "" { - if err := writeFile(gen, p.nexusrpcOut, nexusDoc); err != nil { + if p.openAPIRefPrefix == "" { + addComponentsSchemas(nexusDoc, collector) + } + + if p.nexusRpcOut != "" { + if err := writeFile(gen, p.nexusRpcOut, nexusDoc); err != nil { return err } } - if p.nexusrpcLangsOut != "" { - return writeFile(gen, p.nexusrpcLangsOut, langsDoc) + if p.nexusRpcLangsOut != "" { + return writeFile(gen, p.nexusRpcLangsOut, langsDoc) } return nil } @@ -214,6 +228,273 @@ func langRefs(p params, file protoreflect.FileDescriptor, msg protoreflect.Messa return refs } +// schemaCollector recursively collects JSON Schema nodes for proto message types. +type schemaCollector struct { + schemas map[string]*yaml.Node + visited map[string]bool +} + +func newSchemaCollector() *schemaCollector { + return &schemaCollector{ + schemas: make(map[string]*yaml.Node), + visited: make(map[string]bool), + } +} + +// msgSchemaName converts a proto message full name to a JSON Schema component name. +// It strips the proto package prefix and retains at most the last 2 path segments, +// joining them with "_". This matches the OpenAPI spec naming convention: +// +// temporal.api.common.v1.Payload.ExternalPayloadDetails → Payload_ExternalPayloadDetails +// temporal.api.common.v1.Link.WorkflowEvent.EventReference → WorkflowEvent_EventReference +// temporal.api.common.v1.Link.WorkflowEvent → Link_WorkflowEvent +func msgSchemaName(msg protoreflect.MessageDescriptor) string { + fullName := string(msg.FullName()) + pkg := string(msg.ParentFile().Package()) + if pkg != "" { + fullName = strings.TrimPrefix(fullName, pkg+".") + } + parts := strings.Split(fullName, ".") + if len(parts) > 2 { + parts = parts[len(parts)-2:] + } + return strings.Join(parts, "_") +} + +// collect adds the JSON Schema for msg and all transitively referenced messages to c.schemas. +// Marking visited before processing fields prevents infinite loops from circular references. +func (c *schemaCollector) collect(msg protoreflect.MessageDescriptor) { + name := msgSchemaName(msg) + if c.visited[name] { + return + } + c.visited[name] = true + + objNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + objNode.Content = append(objNode.Content, scalarNode("type"), scalarNode("object")) + + fields := msg.Fields() + if fields.Len() > 0 { + propsNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + for i := 0; i < fields.Len(); i++ { + field := fields.Get(i) + propsNode.Content = append(propsNode.Content, + scalarNode(field.JSONName()), + c.fieldNode(field), + ) + } + objNode.Content = append(objNode.Content, scalarNode("properties"), propsNode) + } + + c.schemas[name] = objNode +} + +// fieldNode returns the JSON Schema node for a single proto field, handling map, +// repeated (list), and singular cardinalities. +func (c *schemaCollector) fieldNode(field protoreflect.FieldDescriptor) *yaml.Node { + if field.IsMap() { + // map → {type: object, additionalProperties: } + valueField := field.Message().Fields().ByName("value") + node := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + node.Content = append(node.Content, + scalarNode("type"), + scalarNode("object"), + scalarNode("additionalProperties"), + c.kindNode(valueField), + ) + return node + } + item := c.kindNode(field) + if field.IsList() { + // repeated T → {type: array, items: } + node := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + node.Content = append(node.Content, + scalarNode("type"), + scalarNode("array"), + scalarNode("items"), + item, + ) + return node + } + return item +} + +// kindNode returns the JSON Schema for the base (scalar/message/enum) type of a field, +// ignoring any repeated/map cardinality wrapping. +func (c *schemaCollector) kindNode(field protoreflect.FieldDescriptor) *yaml.Node { + switch field.Kind() { + case protoreflect.BoolKind: + return typeNode("boolean") + case protoreflect.StringKind: + return typeNode("string") + case protoreflect.BytesKind: + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("string"), + scalarNode("format"), scalarNode("byte"), + ) + return n + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("integer"), + scalarNode("format"), scalarNode("int32"), + ) + return n + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("integer"), + scalarNode("format"), scalarNode("uint32"), + ) + return n + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind, + protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + // protojson encodes 64-bit integers as decimal strings to avoid JS precision loss. + return typeNode("string") + case protoreflect.FloatKind: + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("number"), + scalarNode("format"), scalarNode("float"), + ) + return n + case protoreflect.DoubleKind: + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("number"), + scalarNode("format"), scalarNode("double"), + ) + return n + case protoreflect.EnumKind: + return enumNode(field.Enum()) + case protoreflect.MessageKind, protoreflect.GroupKind: + return c.msgRefNode(field.Message()) + } + return typeNode("object") +} + +// msgRefNode returns an inline schema for well-known proto types, or a $ref for all others. +// It also triggers recursive schema collection for non-well-known message types. +func (c *schemaCollector) msgRefNode(msg protoreflect.MessageDescriptor) *yaml.Node { + switch string(msg.FullName()) { + case "google.protobuf.Duration": + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("string"), + scalarNode("pattern"), scalarNode(`^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$`), + ) + return n + case "google.protobuf.Timestamp": + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("string"), + scalarNode("format"), scalarNode("date-time"), + ) + return n + case "google.protobuf.Empty": + return typeNode("object") + case "google.protobuf.Any", + "google.protobuf.Struct", + "google.protobuf.Value": + return typeNode("object") + case "google.protobuf.ListValue": + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("array"), + scalarNode("items"), typeNode("object"), + ) + return n + case "google.protobuf.BoolValue": + return typeNode("boolean") + case "google.protobuf.StringValue": + return typeNode("string") + case "google.protobuf.BytesValue": + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("string"), + scalarNode("format"), scalarNode("byte"), + ) + return n + case "google.protobuf.Int32Value", + "google.protobuf.UInt32Value": + return typeNode("integer") + case "google.protobuf.Int64Value", + "google.protobuf.UInt64Value": + return typeNode("string") + case "google.protobuf.FloatValue": + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("number"), + scalarNode("format"), scalarNode("float"), + ) + return n + case "google.protobuf.DoubleValue": + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, + scalarNode("type"), scalarNode("number"), + scalarNode("format"), scalarNode("double"), + ) + return n + } + name := msgSchemaName(msg) + c.collect(msg) + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, scalarNode("$ref"), scalarNode("#/components/schemas/"+name)) + return n +} + +// enumNode builds a JSON Schema enum node listing all enum value names. +func enumNode(e protoreflect.EnumDescriptor) *yaml.Node { + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + seqNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + values := e.Values() + for i := 0; i < values.Len(); i++ { + seqNode.Content = append(seqNode.Content, scalarNode(string(values.Get(i).Name()))) + } + n.Content = append(n.Content, + scalarNode("enum"), seqNode, + scalarNode("type"), scalarNode("string"), + scalarNode("format"), scalarNode("enum"), + ) + return n +} + +func typeNode(t string) *yaml.Node { + n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + n.Content = append(n.Content, scalarNode("type"), scalarNode(t)) + return n +} + +// addComponentsSchemas inserts a "components: schemas:" section into doc, positioned +// between the "nexusrpc" version header and the "services" block. Schemas are sorted +// alphabetically for deterministic output. +func addComponentsSchemas(doc *yaml.Node, c *schemaCollector) { + root := doc.Content[0] + + names := make([]string, 0, len(c.schemas)) + for name := range c.schemas { + names = append(names, name) + } + sort.Strings(names) + + schemasNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + for _, name := range names { + schemasNode.Content = append(schemasNode.Content, scalarNode(name), c.schemas[name]) + } + + componentsNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + componentsNode.Content = append(componentsNode.Content, scalarNode("schemas"), schemasNode) + + // root.Content layout: [nexusrpc, 1.0.0, services, {...}] + // After insert: [nexusrpc, 1.0.0, components, {...}, services, {...}] + newContent := make([]*yaml.Node, 0, len(root.Content)+2) + newContent = append(newContent, root.Content[:2]...) + newContent = append(newContent, scalarNode("components"), componentsNode) + newContent = append(newContent, root.Content[2:]...) + root.Content = newContent +} + // newDoc creates a yaml.Node document with the "nexusrpc: 1.0.0" header // and an empty "services" mapping node. func newDoc() *yaml.Node { diff --git a/cmd/protoc-gen-nexus-rpc-yaml/main.go b/cmd/protoc-gen-nexus-rpc-yaml/main.go index 9fadd0fb1..23c3a8e7c 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/main.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/main.go @@ -1,5 +1,5 @@ -// protoc-gen-nexus-rpc-yaml is a protoc plugin that generates nexus/nexusrpc.yaml -// and nexus/nexusrpc.langs.yaml from proto service methods annotated with +// protoc-gen-nexus-rpc-yaml is a protoc plugin that generates nexus/nexus-rpc.yaml +// and nexus/nexus-rpc.langs.yaml from proto service methods annotated with // option (nexusannotations.v1.operation).tags = "exposed". package main diff --git a/nexus/temporal-json-schema-models-nexusrpc.yaml b/nexus/temporal-json-schema-models-nexusrpc.yaml index bbfafb33a..f955c6eb6 100644 --- a/nexus/temporal-json-schema-models-nexusrpc.yaml +++ b/nexus/temporal-json-schema-models-nexusrpc.yaml @@ -1,9 +1,434 @@ nexusrpc: 1.0.0 +components: + schemas: + Deployment: + type: object + properties: + seriesName: + type: string + buildId: + type: string + Header: + type: object + properties: + fields: + type: object + additionalProperties: + $ref: '#/components/schemas/Payload' + Link: + type: object + properties: + workflowEvent: + $ref: '#/components/schemas/Link_WorkflowEvent' + batchJob: + $ref: '#/components/schemas/Link_BatchJob' + activity: + $ref: '#/components/schemas/Link_Activity' + Link_Activity: + type: object + properties: + namespace: + type: string + activityId: + type: string + runId: + type: string + Link_BatchJob: + type: object + properties: + jobId: + type: string + Link_WorkflowEvent: + type: object + properties: + namespace: + type: string + workflowId: + type: string + runId: + type: string + eventRef: + $ref: '#/components/schemas/WorkflowEvent_EventReference' + requestIdRef: + $ref: '#/components/schemas/WorkflowEvent_RequestIdReference' + Memo: + type: object + properties: + fields: + type: object + additionalProperties: + $ref: '#/components/schemas/Payload' + Payload: + type: object + properties: + metadata: + type: object + additionalProperties: + type: string + format: byte + data: + type: string + format: byte + externalPayloads: + type: array + items: + $ref: '#/components/schemas/Payload_ExternalPayloadDetails' + Payload_ExternalPayloadDetails: + type: object + properties: + sizeBytes: + type: string + Payloads: + type: object + properties: + payloads: + type: array + items: + $ref: '#/components/schemas/Payload' + Priority: + type: object + properties: + priorityKey: + type: integer + format: int32 + fairnessKey: + type: string + fairnessWeight: + type: number + format: float + RetryPolicy: + type: object + properties: + initialInterval: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + backoffCoefficient: + type: number + format: double + maximumInterval: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + maximumAttempts: + type: integer + format: int32 + nonRetryableErrorTypes: + type: array + items: + type: string + SearchAttributes: + type: object + properties: + indexedFields: + type: object + additionalProperties: + $ref: '#/components/schemas/Payload' + SignalWithStartWorkflowExecutionRequest: + type: object + properties: + namespace: + type: string + workflowId: + type: string + workflowType: + $ref: '#/components/schemas/WorkflowType' + taskQueue: + $ref: '#/components/schemas/TaskQueue' + input: + $ref: '#/components/schemas/Payloads' + workflowExecutionTimeout: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + workflowRunTimeout: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + workflowTaskTimeout: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + identity: + type: string + requestId: + type: string + workflowIdReusePolicy: + enum: + - WORKFLOW_ID_REUSE_POLICY_UNSPECIFIED + - WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE + - WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY + - WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE + - WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING + type: string + format: enum + workflowIdConflictPolicy: + enum: + - WORKFLOW_ID_CONFLICT_POLICY_UNSPECIFIED + - WORKFLOW_ID_CONFLICT_POLICY_FAIL + - WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING + - WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING + type: string + format: enum + signalName: + type: string + signalInput: + $ref: '#/components/schemas/Payloads' + control: + type: string + retryPolicy: + $ref: '#/components/schemas/RetryPolicy' + cronSchedule: + type: string + memo: + $ref: '#/components/schemas/Memo' + searchAttributes: + $ref: '#/components/schemas/SearchAttributes' + header: + $ref: '#/components/schemas/Header' + workflowStartDelay: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + userMetadata: + $ref: '#/components/schemas/UserMetadata' + links: + type: array + items: + $ref: '#/components/schemas/Link' + versioningOverride: + $ref: '#/components/schemas/VersioningOverride' + priority: + $ref: '#/components/schemas/Priority' + timeSkippingConfig: + $ref: '#/components/schemas/TimeSkippingConfig' + SignalWithStartWorkflowExecutionResponse: + type: object + properties: + runId: + type: string + started: + type: boolean + signalLink: + $ref: '#/components/schemas/Link' + TaskQueue: + type: object + properties: + name: + type: string + kind: + enum: + - TASK_QUEUE_KIND_UNSPECIFIED + - TASK_QUEUE_KIND_NORMAL + - TASK_QUEUE_KIND_STICKY + - TASK_QUEUE_KIND_WORKER_COMMANDS + type: string + format: enum + normalName: + type: string + TimeSkippingConfig: + type: object + properties: + enabled: + type: boolean + disablePropagation: + type: boolean + maxSkippedDuration: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + maxElapsedDuration: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + maxTargetTime: + type: string + format: date-time + UserMetadata: + type: object + properties: + summary: + $ref: '#/components/schemas/Payload' + details: + $ref: '#/components/schemas/Payload' + VersioningOverride: + type: object + properties: + pinned: + $ref: '#/components/schemas/VersioningOverride_PinnedOverride' + autoUpgrade: + type: boolean + behavior: + enum: + - VERSIONING_BEHAVIOR_UNSPECIFIED + - VERSIONING_BEHAVIOR_PINNED + - VERSIONING_BEHAVIOR_AUTO_UPGRADE + type: string + format: enum + deployment: + $ref: '#/components/schemas/Deployment' + pinnedVersion: + type: string + VersioningOverride_PinnedOverride: + type: object + properties: + behavior: + enum: + - PINNED_OVERRIDE_BEHAVIOR_UNSPECIFIED + - PINNED_OVERRIDE_BEHAVIOR_PINNED + type: string + format: enum + version: + $ref: '#/components/schemas/WorkerDeploymentVersion' + WorkerDeploymentVersion: + type: object + properties: + buildId: + type: string + deploymentName: + type: string + WorkflowEvent_EventReference: + type: object + properties: + eventId: + type: string + eventType: + enum: + - EVENT_TYPE_UNSPECIFIED + - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED + - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED + - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT + - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED + - EVENT_TYPE_WORKFLOW_TASK_STARTED + - EVENT_TYPE_WORKFLOW_TASK_COMPLETED + - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT + - EVENT_TYPE_WORKFLOW_TASK_FAILED + - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED + - EVENT_TYPE_ACTIVITY_TASK_STARTED + - EVENT_TYPE_ACTIVITY_TASK_COMPLETED + - EVENT_TYPE_ACTIVITY_TASK_FAILED + - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT + - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED + - EVENT_TYPE_ACTIVITY_TASK_CANCELED + - EVENT_TYPE_TIMER_STARTED + - EVENT_TYPE_TIMER_FIRED + - EVENT_TYPE_TIMER_CANCELED + - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED + - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED + - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED + - EVENT_TYPE_MARKER_RECORDED + - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED + - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED + - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW + - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED + - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED + - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED + - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY + - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY + - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED + - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED + - EVENT_TYPE_NEXUS_OPERATION_STARTED + - EVENT_TYPE_NEXUS_OPERATION_COMPLETED + - EVENT_TYPE_NEXUS_OPERATION_FAILED + - EVENT_TYPE_NEXUS_OPERATION_CANCELED + - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED + - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED + - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED + - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED + - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED + type: string + format: enum + WorkflowEvent_RequestIdReference: + type: object + properties: + requestId: + type: string + eventType: + enum: + - EVENT_TYPE_UNSPECIFIED + - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED + - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED + - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT + - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED + - EVENT_TYPE_WORKFLOW_TASK_STARTED + - EVENT_TYPE_WORKFLOW_TASK_COMPLETED + - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT + - EVENT_TYPE_WORKFLOW_TASK_FAILED + - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED + - EVENT_TYPE_ACTIVITY_TASK_STARTED + - EVENT_TYPE_ACTIVITY_TASK_COMPLETED + - EVENT_TYPE_ACTIVITY_TASK_FAILED + - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT + - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED + - EVENT_TYPE_ACTIVITY_TASK_CANCELED + - EVENT_TYPE_TIMER_STARTED + - EVENT_TYPE_TIMER_FIRED + - EVENT_TYPE_TIMER_CANCELED + - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED + - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED + - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED + - EVENT_TYPE_MARKER_RECORDED + - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED + - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED + - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW + - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED + - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED + - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED + - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY + - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY + - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED + - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED + - EVENT_TYPE_NEXUS_OPERATION_STARTED + - EVENT_TYPE_NEXUS_OPERATION_COMPLETED + - EVENT_TYPE_NEXUS_OPERATION_FAILED + - EVENT_TYPE_NEXUS_OPERATION_CANCELED + - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED + - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED + - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED + - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED + - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED + type: string + format: enum + WorkflowType: + type: object + properties: + name: + type: string services: WorkflowService: operations: SignalWithStartWorkflowExecution: input: - $ref: ../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionRequest + $ref: '#/components/schemas/SignalWithStartWorkflowExecutionRequest' output: - $ref: ../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionResponse + $ref: '#/components/schemas/SignalWithStartWorkflowExecutionResponse' From 0e58e7d32d58c6142cc0615f4c8045078e17f683 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Fri, 17 Apr 2026 14:50:50 -0400 Subject: [PATCH 19/22] /components/schemas -> /types --- cmd/protoc-gen-nexus-rpc-yaml/generator.go | 27 +- .../temporal-json-schema-models-nexusrpc.yaml | 849 +++++++++--------- 2 files changed, 436 insertions(+), 440 deletions(-) diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go index 1643b8060..3b9ed1c4b 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -19,7 +19,7 @@ import ( // // - openapi_ref_prefix: optional. When set, nexus-rpc_out emits a bare $ref to the OpenAPI // schema rather than inlining schemas under components/schemas. -// Example: "../openapi/openapiv3.yaml#/components/schemas/" +// Example: "../openapi/openapiv3.yaml#/types/" // // - nexus-rpc_out: optional. Output path for nexus-rpc.yaml (relative to --nexus-rpc-yaml_out dir). // If empty, nexus-rpc.yaml is not written. @@ -150,8 +150,8 @@ func generate(gen *protogen.Plugin) error { collector.collect(m.Input.Desc) collector.collect(m.Output.Desc) addOperation(nexusDoc, svcName, methodName, - map[string]string{"$ref": "#/components/schemas/" + inputName}, - map[string]string{"$ref": "#/components/schemas/" + outputName}, + map[string]string{"$ref": "#/types/" + inputName}, + map[string]string{"$ref": "#/types/" + outputName}, ) } @@ -168,7 +168,7 @@ func generate(gen *protogen.Plugin) error { } if p.openAPIRefPrefix == "" { - addComponentsSchemas(nexusDoc, collector) + addTypes(nexusDoc, collector) } if p.nexusRpcOut != "" { @@ -440,7 +440,7 @@ func (c *schemaCollector) msgRefNode(msg protoreflect.MessageDescriptor) *yaml.N name := msgSchemaName(msg) c.collect(msg) n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, scalarNode("$ref"), scalarNode("#/components/schemas/"+name)) + n.Content = append(n.Content, scalarNode("$ref"), scalarNode("#/types/"+name)) return n } @@ -466,10 +466,10 @@ func typeNode(t string) *yaml.Node { return n } -// addComponentsSchemas inserts a "components: schemas:" section into doc, positioned -// between the "nexusrpc" version header and the "services" block. Schemas are sorted +// addTypes inserts a "types:" section into doc, positioned between the +// "nexusrpc" version header and the "services" block. Types are sorted // alphabetically for deterministic output. -func addComponentsSchemas(doc *yaml.Node, c *schemaCollector) { +func addTypes(doc *yaml.Node, c *schemaCollector) { root := doc.Content[0] names := make([]string, 0, len(c.schemas)) @@ -478,19 +478,16 @@ func addComponentsSchemas(doc *yaml.Node, c *schemaCollector) { } sort.Strings(names) - schemasNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + typesNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} for _, name := range names { - schemasNode.Content = append(schemasNode.Content, scalarNode(name), c.schemas[name]) + typesNode.Content = append(typesNode.Content, scalarNode(name), c.schemas[name]) } - componentsNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - componentsNode.Content = append(componentsNode.Content, scalarNode("schemas"), schemasNode) - // root.Content layout: [nexusrpc, 1.0.0, services, {...}] - // After insert: [nexusrpc, 1.0.0, components, {...}, services, {...}] + // After insert: [nexusrpc, 1.0.0, types, {...}, services, {...}] newContent := make([]*yaml.Node, 0, len(root.Content)+2) newContent = append(newContent, root.Content[:2]...) - newContent = append(newContent, scalarNode("components"), componentsNode) + newContent = append(newContent, scalarNode("types"), typesNode) newContent = append(newContent, root.Content[2:]...) root.Content = newContent } diff --git a/nexus/temporal-json-schema-models-nexusrpc.yaml b/nexus/temporal-json-schema-models-nexusrpc.yaml index f955c6eb6..63ae97536 100644 --- a/nexus/temporal-json-schema-models-nexusrpc.yaml +++ b/nexus/temporal-json-schema-models-nexusrpc.yaml @@ -1,434 +1,433 @@ nexusrpc: 1.0.0 -components: - schemas: - Deployment: - type: object - properties: - seriesName: - type: string - buildId: - type: string - Header: - type: object - properties: - fields: - type: object - additionalProperties: - $ref: '#/components/schemas/Payload' - Link: - type: object - properties: - workflowEvent: - $ref: '#/components/schemas/Link_WorkflowEvent' - batchJob: - $ref: '#/components/schemas/Link_BatchJob' - activity: - $ref: '#/components/schemas/Link_Activity' - Link_Activity: - type: object - properties: - namespace: - type: string - activityId: - type: string - runId: - type: string - Link_BatchJob: - type: object - properties: - jobId: - type: string - Link_WorkflowEvent: - type: object - properties: - namespace: - type: string - workflowId: - type: string - runId: - type: string - eventRef: - $ref: '#/components/schemas/WorkflowEvent_EventReference' - requestIdRef: - $ref: '#/components/schemas/WorkflowEvent_RequestIdReference' - Memo: - type: object - properties: - fields: - type: object - additionalProperties: - $ref: '#/components/schemas/Payload' - Payload: - type: object - properties: - metadata: - type: object - additionalProperties: - type: string - format: byte - data: +types: + Deployment: + type: object + properties: + seriesName: + type: string + buildId: + type: string + Header: + type: object + properties: + fields: + type: object + additionalProperties: + $ref: '#/types/Payload' + Link: + type: object + properties: + workflowEvent: + $ref: '#/types/Link_WorkflowEvent' + batchJob: + $ref: '#/types/Link_BatchJob' + activity: + $ref: '#/types/Link_Activity' + Link_Activity: + type: object + properties: + namespace: + type: string + activityId: + type: string + runId: + type: string + Link_BatchJob: + type: object + properties: + jobId: + type: string + Link_WorkflowEvent: + type: object + properties: + namespace: + type: string + workflowId: + type: string + runId: + type: string + eventRef: + $ref: '#/types/WorkflowEvent_EventReference' + requestIdRef: + $ref: '#/types/WorkflowEvent_RequestIdReference' + Memo: + type: object + properties: + fields: + type: object + additionalProperties: + $ref: '#/types/Payload' + Payload: + type: object + properties: + metadata: + type: object + additionalProperties: type: string format: byte - externalPayloads: - type: array - items: - $ref: '#/components/schemas/Payload_ExternalPayloadDetails' - Payload_ExternalPayloadDetails: - type: object - properties: - sizeBytes: - type: string - Payloads: - type: object - properties: - payloads: - type: array - items: - $ref: '#/components/schemas/Payload' - Priority: - type: object - properties: - priorityKey: - type: integer - format: int32 - fairnessKey: - type: string - fairnessWeight: - type: number - format: float - RetryPolicy: - type: object - properties: - initialInterval: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - backoffCoefficient: - type: number - format: double - maximumInterval: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - maximumAttempts: - type: integer - format: int32 - nonRetryableErrorTypes: - type: array - items: - type: string - SearchAttributes: - type: object - properties: - indexedFields: - type: object - additionalProperties: - $ref: '#/components/schemas/Payload' - SignalWithStartWorkflowExecutionRequest: - type: object - properties: - namespace: - type: string - workflowId: - type: string - workflowType: - $ref: '#/components/schemas/WorkflowType' - taskQueue: - $ref: '#/components/schemas/TaskQueue' - input: - $ref: '#/components/schemas/Payloads' - workflowExecutionTimeout: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - workflowRunTimeout: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - workflowTaskTimeout: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - identity: - type: string - requestId: - type: string - workflowIdReusePolicy: - enum: - - WORKFLOW_ID_REUSE_POLICY_UNSPECIFIED - - WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE - - WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY - - WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE - - WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING - type: string - format: enum - workflowIdConflictPolicy: - enum: - - WORKFLOW_ID_CONFLICT_POLICY_UNSPECIFIED - - WORKFLOW_ID_CONFLICT_POLICY_FAIL - - WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING - - WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING - type: string - format: enum - signalName: - type: string - signalInput: - $ref: '#/components/schemas/Payloads' - control: - type: string - retryPolicy: - $ref: '#/components/schemas/RetryPolicy' - cronSchedule: - type: string - memo: - $ref: '#/components/schemas/Memo' - searchAttributes: - $ref: '#/components/schemas/SearchAttributes' - header: - $ref: '#/components/schemas/Header' - workflowStartDelay: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - userMetadata: - $ref: '#/components/schemas/UserMetadata' - links: - type: array - items: - $ref: '#/components/schemas/Link' - versioningOverride: - $ref: '#/components/schemas/VersioningOverride' - priority: - $ref: '#/components/schemas/Priority' - timeSkippingConfig: - $ref: '#/components/schemas/TimeSkippingConfig' - SignalWithStartWorkflowExecutionResponse: - type: object - properties: - runId: - type: string - started: - type: boolean - signalLink: - $ref: '#/components/schemas/Link' - TaskQueue: - type: object - properties: - name: - type: string - kind: - enum: - - TASK_QUEUE_KIND_UNSPECIFIED - - TASK_QUEUE_KIND_NORMAL - - TASK_QUEUE_KIND_STICKY - - TASK_QUEUE_KIND_WORKER_COMMANDS - type: string - format: enum - normalName: - type: string - TimeSkippingConfig: - type: object - properties: - enabled: - type: boolean - disablePropagation: - type: boolean - maxSkippedDuration: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - maxElapsedDuration: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - maxTargetTime: - type: string - format: date-time - UserMetadata: - type: object - properties: - summary: - $ref: '#/components/schemas/Payload' - details: - $ref: '#/components/schemas/Payload' - VersioningOverride: - type: object - properties: - pinned: - $ref: '#/components/schemas/VersioningOverride_PinnedOverride' - autoUpgrade: - type: boolean - behavior: - enum: - - VERSIONING_BEHAVIOR_UNSPECIFIED - - VERSIONING_BEHAVIOR_PINNED - - VERSIONING_BEHAVIOR_AUTO_UPGRADE - type: string - format: enum - deployment: - $ref: '#/components/schemas/Deployment' - pinnedVersion: - type: string - VersioningOverride_PinnedOverride: - type: object - properties: - behavior: - enum: - - PINNED_OVERRIDE_BEHAVIOR_UNSPECIFIED - - PINNED_OVERRIDE_BEHAVIOR_PINNED - type: string - format: enum - version: - $ref: '#/components/schemas/WorkerDeploymentVersion' - WorkerDeploymentVersion: - type: object - properties: - buildId: - type: string - deploymentName: - type: string - WorkflowEvent_EventReference: - type: object - properties: - eventId: - type: string - eventType: - enum: - - EVENT_TYPE_UNSPECIFIED - - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED - - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED - - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT - - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED - - EVENT_TYPE_WORKFLOW_TASK_STARTED - - EVENT_TYPE_WORKFLOW_TASK_COMPLETED - - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT - - EVENT_TYPE_WORKFLOW_TASK_FAILED - - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED - - EVENT_TYPE_ACTIVITY_TASK_STARTED - - EVENT_TYPE_ACTIVITY_TASK_COMPLETED - - EVENT_TYPE_ACTIVITY_TASK_FAILED - - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT - - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED - - EVENT_TYPE_ACTIVITY_TASK_CANCELED - - EVENT_TYPE_TIMER_STARTED - - EVENT_TYPE_TIMER_FIRED - - EVENT_TYPE_TIMER_CANCELED - - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED - - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED - - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED - - EVENT_TYPE_MARKER_RECORDED - - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED - - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED - - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW - - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED - - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED - - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED - - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY - - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY - - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED - - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED - - EVENT_TYPE_NEXUS_OPERATION_STARTED - - EVENT_TYPE_NEXUS_OPERATION_COMPLETED - - EVENT_TYPE_NEXUS_OPERATION_FAILED - - EVENT_TYPE_NEXUS_OPERATION_CANCELED - - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED - - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED - - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED - - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED - type: string - format: enum - WorkflowEvent_RequestIdReference: - type: object - properties: - requestId: - type: string - eventType: - enum: - - EVENT_TYPE_UNSPECIFIED - - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED - - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED - - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT - - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED - - EVENT_TYPE_WORKFLOW_TASK_STARTED - - EVENT_TYPE_WORKFLOW_TASK_COMPLETED - - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT - - EVENT_TYPE_WORKFLOW_TASK_FAILED - - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED - - EVENT_TYPE_ACTIVITY_TASK_STARTED - - EVENT_TYPE_ACTIVITY_TASK_COMPLETED - - EVENT_TYPE_ACTIVITY_TASK_FAILED - - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT - - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED - - EVENT_TYPE_ACTIVITY_TASK_CANCELED - - EVENT_TYPE_TIMER_STARTED - - EVENT_TYPE_TIMER_FIRED - - EVENT_TYPE_TIMER_CANCELED - - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED - - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED - - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED - - EVENT_TYPE_MARKER_RECORDED - - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED - - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED - - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW - - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED - - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED - - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED - - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY - - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY - - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED - - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED - - EVENT_TYPE_NEXUS_OPERATION_STARTED - - EVENT_TYPE_NEXUS_OPERATION_COMPLETED - - EVENT_TYPE_NEXUS_OPERATION_FAILED - - EVENT_TYPE_NEXUS_OPERATION_CANCELED - - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED - - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED - - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED - - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED - type: string - format: enum - WorkflowType: - type: object - properties: - name: - type: string + data: + type: string + format: byte + externalPayloads: + type: array + items: + $ref: '#/types/Payload_ExternalPayloadDetails' + Payload_ExternalPayloadDetails: + type: object + properties: + sizeBytes: + type: string + Payloads: + type: object + properties: + payloads: + type: array + items: + $ref: '#/types/Payload' + Priority: + type: object + properties: + priorityKey: + type: integer + format: int32 + fairnessKey: + type: string + fairnessWeight: + type: number + format: float + RetryPolicy: + type: object + properties: + initialInterval: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + backoffCoefficient: + type: number + format: double + maximumInterval: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + maximumAttempts: + type: integer + format: int32 + nonRetryableErrorTypes: + type: array + items: + type: string + SearchAttributes: + type: object + properties: + indexedFields: + type: object + additionalProperties: + $ref: '#/types/Payload' + SignalWithStartWorkflowExecutionRequest: + type: object + properties: + namespace: + type: string + workflowId: + type: string + workflowType: + $ref: '#/types/WorkflowType' + taskQueue: + $ref: '#/types/TaskQueue' + input: + $ref: '#/types/Payloads' + workflowExecutionTimeout: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + workflowRunTimeout: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + workflowTaskTimeout: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + identity: + type: string + requestId: + type: string + workflowIdReusePolicy: + enum: + - WORKFLOW_ID_REUSE_POLICY_UNSPECIFIED + - WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE + - WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY + - WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE + - WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING + type: string + format: enum + workflowIdConflictPolicy: + enum: + - WORKFLOW_ID_CONFLICT_POLICY_UNSPECIFIED + - WORKFLOW_ID_CONFLICT_POLICY_FAIL + - WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING + - WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING + type: string + format: enum + signalName: + type: string + signalInput: + $ref: '#/types/Payloads' + control: + type: string + retryPolicy: + $ref: '#/types/RetryPolicy' + cronSchedule: + type: string + memo: + $ref: '#/types/Memo' + searchAttributes: + $ref: '#/types/SearchAttributes' + header: + $ref: '#/types/Header' + workflowStartDelay: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + userMetadata: + $ref: '#/types/UserMetadata' + links: + type: array + items: + $ref: '#/types/Link' + versioningOverride: + $ref: '#/types/VersioningOverride' + priority: + $ref: '#/types/Priority' + timeSkippingConfig: + $ref: '#/types/TimeSkippingConfig' + SignalWithStartWorkflowExecutionResponse: + type: object + properties: + runId: + type: string + started: + type: boolean + signalLink: + $ref: '#/types/Link' + TaskQueue: + type: object + properties: + name: + type: string + kind: + enum: + - TASK_QUEUE_KIND_UNSPECIFIED + - TASK_QUEUE_KIND_NORMAL + - TASK_QUEUE_KIND_STICKY + - TASK_QUEUE_KIND_WORKER_COMMANDS + type: string + format: enum + normalName: + type: string + TimeSkippingConfig: + type: object + properties: + enabled: + type: boolean + disablePropagation: + type: boolean + maxSkippedDuration: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + maxElapsedDuration: + type: string + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + maxTargetTime: + type: string + format: date-time + UserMetadata: + type: object + properties: + summary: + $ref: '#/types/Payload' + details: + $ref: '#/types/Payload' + VersioningOverride: + type: object + properties: + pinned: + $ref: '#/types/VersioningOverride_PinnedOverride' + autoUpgrade: + type: boolean + behavior: + enum: + - VERSIONING_BEHAVIOR_UNSPECIFIED + - VERSIONING_BEHAVIOR_PINNED + - VERSIONING_BEHAVIOR_AUTO_UPGRADE + type: string + format: enum + deployment: + $ref: '#/types/Deployment' + pinnedVersion: + type: string + VersioningOverride_PinnedOverride: + type: object + properties: + behavior: + enum: + - PINNED_OVERRIDE_BEHAVIOR_UNSPECIFIED + - PINNED_OVERRIDE_BEHAVIOR_PINNED + type: string + format: enum + version: + $ref: '#/types/WorkerDeploymentVersion' + WorkerDeploymentVersion: + type: object + properties: + buildId: + type: string + deploymentName: + type: string + WorkflowEvent_EventReference: + type: object + properties: + eventId: + type: string + eventType: + enum: + - EVENT_TYPE_UNSPECIFIED + - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED + - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED + - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT + - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED + - EVENT_TYPE_WORKFLOW_TASK_STARTED + - EVENT_TYPE_WORKFLOW_TASK_COMPLETED + - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT + - EVENT_TYPE_WORKFLOW_TASK_FAILED + - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED + - EVENT_TYPE_ACTIVITY_TASK_STARTED + - EVENT_TYPE_ACTIVITY_TASK_COMPLETED + - EVENT_TYPE_ACTIVITY_TASK_FAILED + - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT + - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED + - EVENT_TYPE_ACTIVITY_TASK_CANCELED + - EVENT_TYPE_TIMER_STARTED + - EVENT_TYPE_TIMER_FIRED + - EVENT_TYPE_TIMER_CANCELED + - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED + - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED + - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED + - EVENT_TYPE_MARKER_RECORDED + - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED + - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED + - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW + - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED + - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED + - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED + - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY + - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY + - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED + - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED + - EVENT_TYPE_NEXUS_OPERATION_STARTED + - EVENT_TYPE_NEXUS_OPERATION_COMPLETED + - EVENT_TYPE_NEXUS_OPERATION_FAILED + - EVENT_TYPE_NEXUS_OPERATION_CANCELED + - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED + - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED + - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED + - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED + - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED + type: string + format: enum + WorkflowEvent_RequestIdReference: + type: object + properties: + requestId: + type: string + eventType: + enum: + - EVENT_TYPE_UNSPECIFIED + - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED + - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED + - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT + - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED + - EVENT_TYPE_WORKFLOW_TASK_STARTED + - EVENT_TYPE_WORKFLOW_TASK_COMPLETED + - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT + - EVENT_TYPE_WORKFLOW_TASK_FAILED + - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED + - EVENT_TYPE_ACTIVITY_TASK_STARTED + - EVENT_TYPE_ACTIVITY_TASK_COMPLETED + - EVENT_TYPE_ACTIVITY_TASK_FAILED + - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT + - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED + - EVENT_TYPE_ACTIVITY_TASK_CANCELED + - EVENT_TYPE_TIMER_STARTED + - EVENT_TYPE_TIMER_FIRED + - EVENT_TYPE_TIMER_CANCELED + - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED + - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED + - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED + - EVENT_TYPE_MARKER_RECORDED + - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED + - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED + - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW + - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT + - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED + - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED + - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED + - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED + - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED + - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED + - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY + - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY + - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED + - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED + - EVENT_TYPE_NEXUS_OPERATION_STARTED + - EVENT_TYPE_NEXUS_OPERATION_COMPLETED + - EVENT_TYPE_NEXUS_OPERATION_FAILED + - EVENT_TYPE_NEXUS_OPERATION_CANCELED + - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED + - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED + - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED + - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED + - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED + - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED + type: string + format: enum + WorkflowType: + type: object + properties: + name: + type: string services: WorkflowService: operations: SignalWithStartWorkflowExecution: input: - $ref: '#/components/schemas/SignalWithStartWorkflowExecutionRequest' + $ref: '#/types/SignalWithStartWorkflowExecutionRequest' output: - $ref: '#/components/schemas/SignalWithStartWorkflowExecutionResponse' + $ref: '#/types/SignalWithStartWorkflowExecutionResponse' From c6d680874e7253e957fe79687843651ba10e5d22 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Tue, 21 Apr 2026 15:12:40 -0400 Subject: [PATCH 20/22] generate proto refs for grpc requests and responses --- cmd/protoc-gen-nexus-rpc-yaml/generator.go | 44 ++++++++++++++++--- .../temporal-json-schema-models-nexusrpc.yaml | 12 +++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go index 3b9ed1c4b..f44043e7f 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -149,6 +149,12 @@ func generate(gen *protogen.Plugin) error { outputName := msgSchemaName(m.Output.Desc) collector.collect(m.Input.Desc) collector.collect(m.Output.Desc) + if refs := protoRefMap(langRefs(p, f.Desc, m.Input.Desc)); refs != nil { + collector.protoRefs[inputName] = refs + } + if refs := protoRefMap(langRefs(p, f.Desc, m.Output.Desc)); refs != nil { + collector.protoRefs[outputName] = refs + } addOperation(nexusDoc, svcName, methodName, map[string]string{"$ref": "#/types/" + inputName}, map[string]string{"$ref": "#/types/" + outputName}, @@ -230,17 +236,32 @@ func langRefs(p params, file protoreflect.FileDescriptor, msg protoreflect.Messa // schemaCollector recursively collects JSON Schema nodes for proto message types. type schemaCollector struct { - schemas map[string]*yaml.Node - visited map[string]bool + schemas map[string]*yaml.Node + visited map[string]bool + protoRefs map[string]map[string]string // schema name → {$goProtoRef: ..., $pythonProtoRef: ...} } func newSchemaCollector() *schemaCollector { return &schemaCollector{ - schemas: make(map[string]*yaml.Node), - visited: make(map[string]bool), + schemas: make(map[string]*yaml.Node), + visited: make(map[string]bool), + protoRefs: make(map[string]map[string]string), } } +// protoRefMap converts a langRefs map (keys like $goRef, $pythonRef) to proto ref keys +// ($goProtoRef, $pythonProtoRef, …). Returns nil if refs is empty. +func protoRefMap(refs map[string]string) map[string]string { + if len(refs) == 0 { + return nil + } + result := make(map[string]string, len(refs)) + for k, v := range refs { + result[strings.TrimSuffix(k, "Ref")+"ProtoRef"] = v + } + return result +} + // msgSchemaName converts a proto message full name to a JSON Schema component name. // It strips the proto package prefix and retains at most the last 2 path segments, // joining them with "_". This matches the OpenAPI spec naming convention: @@ -480,7 +501,20 @@ func addTypes(doc *yaml.Node, c *schemaCollector) { typesNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} for _, name := range names { - typesNode.Content = append(typesNode.Content, scalarNode(name), c.schemas[name]) + schema := c.schemas[name] + if refs, ok := c.protoRefs[name]; ok { + refKeys := make([]string, 0, len(refs)) + for k := range refs { + refKeys = append(refKeys, k) + } + sort.Strings(refKeys) + prefix := make([]*yaml.Node, 0, 2*len(refs)) + for _, k := range refKeys { + prefix = append(prefix, scalarNode(k), scalarNode(refs[k])) + } + schema.Content = append(prefix, schema.Content...) + } + typesNode.Content = append(typesNode.Content, scalarNode(name), schema) } // root.Content layout: [nexusrpc, 1.0.0, services, {...}] diff --git a/nexus/temporal-json-schema-models-nexusrpc.yaml b/nexus/temporal-json-schema-models-nexusrpc.yaml index 63ae97536..924e448af 100644 --- a/nexus/temporal-json-schema-models-nexusrpc.yaml +++ b/nexus/temporal-json-schema-models-nexusrpc.yaml @@ -122,6 +122,12 @@ types: additionalProperties: $ref: '#/types/Payload' SignalWithStartWorkflowExecutionRequest: + $dotnetProtoRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionRequest + $goProtoRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionRequest + $javaProtoRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest + $pythonProtoRef: temporalio.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest + $rubyProtoRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionRequest + $typescriptProtoRef: '@temporalio/api/workflowservice/v1.SignalWithStartWorkflowExecutionRequest' type: object properties: namespace: @@ -196,6 +202,12 @@ types: timeSkippingConfig: $ref: '#/types/TimeSkippingConfig' SignalWithStartWorkflowExecutionResponse: + $dotnetProtoRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionResponse + $goProtoRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse + $javaProtoRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse + $pythonProtoRef: temporalio.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse + $rubyProtoRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionResponse + $typescriptProtoRef: '@temporalio/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse' type: object properties: runId: From 8f6ab1fd78941aa36b1696705e85977d5c5566c5 Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Mon, 27 Apr 2026 13:28:28 -0400 Subject: [PATCH 21/22] remove json schema definitions --- Makefile | 3 +- cmd/protoc-gen-nexus-rpc-yaml/generator.go | 348 +------------- cmd/protoc-gen-nexus-rpc-yaml/main.go | 5 +- .../temporal-json-schema-models-nexusrpc.yaml | 445 ------------------ 4 files changed, 6 insertions(+), 795 deletions(-) delete mode 100644 nexus/temporal-json-schema-models-nexusrpc.yaml diff --git a/Makefile b/Makefile index e88f9fca5..aa3a5f11f 100644 --- a/Makefile +++ b/Makefile @@ -122,10 +122,9 @@ buf-breaking: @(cd $(PROTO_ROOT) && buf breaking --against 'https://github.com/temporalio/api.git#branch=master') nexus-rpc-yaml: nexus-rpc-yaml-install - printf $(COLOR) "Generate nexus/temporal-json-schema-models-nexusrpc.yaml and nexus/temporal-proto-models-nexusrpc.yaml..." + printf $(COLOR) "Generate nexus/temporal-proto-models-nexusrpc.yaml..." mkdir -p nexus protoc -I $(PROTO_ROOT) \ - --nexus-rpc-yaml_opt=nexus-rpc_out=nexus/temporal-json-schema-models-nexusrpc.yaml \ --nexus-rpc-yaml_opt=nexus-rpc_langs_out=nexus/temporal-proto-models-nexusrpc.yaml \ --nexus-rpc-yaml_opt=python_package_prefix=temporalio.api \ --nexus-rpc-yaml_opt=typescript_package_prefix=@temporalio/api \ diff --git a/cmd/protoc-gen-nexus-rpc-yaml/generator.go b/cmd/protoc-gen-nexus-rpc-yaml/generator.go index f44043e7f..2e4a939c8 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/generator.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/generator.go @@ -17,17 +17,9 @@ import ( // params holds the parsed protoc plugin options. // Passed via --nexus-rpc-yaml_opt=key=value (multiple opts are comma-joined by protoc). // -// - openapi_ref_prefix: optional. When set, nexus-rpc_out emits a bare $ref to the OpenAPI -// schema rather than inlining schemas under components/schemas. -// Example: "../openapi/openapiv3.yaml#/types/" -// -// - nexus-rpc_out: optional. Output path for nexus-rpc.yaml (relative to --nexus-rpc-yaml_out dir). -// If empty, nexus-rpc.yaml is not written. -// Example: "nexus/nexus-rpc.yaml" -// -// - nexus-rpc_langs_out: optional. Output path for nexus-rpc.langs.yaml. -// If empty, nexus-rpc.langs.yaml is not written. -// Example: "nexus/nexus-rpc.langs.yaml" +// - nexus-rpc_langs_out: optional. Output path for the langs YAML. +// If empty, nothing is written. +// Example: "nexus/temporal-proto-models-nexusrpc.yaml" // // - python_package_prefix: optional. Dot-separated package prefix for $pythonRef. // The last two path segments of the go_package ({service}/v{n}) are appended. @@ -48,8 +40,6 @@ import ( // any of these values. Applied after include_operation_tags. // Example: exclude_operation_tags=internal type params struct { - openAPIRefPrefix string - nexusRpcOut string nexusRpcLangsOut string pythonPackagePrefix string typescriptPackagePrefix string @@ -69,10 +59,6 @@ func parseParams(raw string) (params, error) { return p, fmt.Errorf("invalid parameter %q: expected key=value", kv) } switch key { - case "openapi_ref_prefix": - p.openAPIRefPrefix = value - case "nexus-rpc_out": - p.nexusRpcOut = value case "nexus-rpc_langs_out": p.nexusRpcLangsOut = value case "python_package_prefix": @@ -120,10 +106,8 @@ func generate(gen *protogen.Plugin) error { return err } - nexusDoc := newDoc() langsDoc := newDoc() hasOps := false - collector := newSchemaCollector() for _, f := range gen.Files { if !f.Generate { @@ -134,33 +118,9 @@ func generate(gen *protogen.Plugin) error { if !shouldIncludeOperation(p, m) { continue } - svcName := string(svc.Desc.Name()) methodName := string(m.Desc.Name()) hasOps = true - - if p.openAPIRefPrefix != "" { - addOperation(nexusDoc, svcName, methodName, - map[string]string{"$ref": p.openAPIRefPrefix + string(m.Input.Desc.Name())}, - map[string]string{"$ref": p.openAPIRefPrefix + string(m.Output.Desc.Name())}, - ) - } else { - inputName := msgSchemaName(m.Input.Desc) - outputName := msgSchemaName(m.Output.Desc) - collector.collect(m.Input.Desc) - collector.collect(m.Output.Desc) - if refs := protoRefMap(langRefs(p, f.Desc, m.Input.Desc)); refs != nil { - collector.protoRefs[inputName] = refs - } - if refs := protoRefMap(langRefs(p, f.Desc, m.Output.Desc)); refs != nil { - collector.protoRefs[outputName] = refs - } - addOperation(nexusDoc, svcName, methodName, - map[string]string{"$ref": "#/types/" + inputName}, - map[string]string{"$ref": "#/types/" + outputName}, - ) - } - addOperation(langsDoc, svcName, methodName, langRefs(p, f.Desc, m.Input.Desc), langRefs(p, f.Desc, m.Output.Desc), @@ -172,16 +132,6 @@ func generate(gen *protogen.Plugin) error { if !hasOps { return nil } - - if p.openAPIRefPrefix == "" { - addTypes(nexusDoc, collector) - } - - if p.nexusRpcOut != "" { - if err := writeFile(gen, p.nexusRpcOut, nexusDoc); err != nil { - return err - } - } if p.nexusRpcLangsOut != "" { return writeFile(gen, p.nexusRpcLangsOut, langsDoc) } @@ -234,298 +184,6 @@ func langRefs(p params, file protoreflect.FileDescriptor, msg protoreflect.Messa return refs } -// schemaCollector recursively collects JSON Schema nodes for proto message types. -type schemaCollector struct { - schemas map[string]*yaml.Node - visited map[string]bool - protoRefs map[string]map[string]string // schema name → {$goProtoRef: ..., $pythonProtoRef: ...} -} - -func newSchemaCollector() *schemaCollector { - return &schemaCollector{ - schemas: make(map[string]*yaml.Node), - visited: make(map[string]bool), - protoRefs: make(map[string]map[string]string), - } -} - -// protoRefMap converts a langRefs map (keys like $goRef, $pythonRef) to proto ref keys -// ($goProtoRef, $pythonProtoRef, …). Returns nil if refs is empty. -func protoRefMap(refs map[string]string) map[string]string { - if len(refs) == 0 { - return nil - } - result := make(map[string]string, len(refs)) - for k, v := range refs { - result[strings.TrimSuffix(k, "Ref")+"ProtoRef"] = v - } - return result -} - -// msgSchemaName converts a proto message full name to a JSON Schema component name. -// It strips the proto package prefix and retains at most the last 2 path segments, -// joining them with "_". This matches the OpenAPI spec naming convention: -// -// temporal.api.common.v1.Payload.ExternalPayloadDetails → Payload_ExternalPayloadDetails -// temporal.api.common.v1.Link.WorkflowEvent.EventReference → WorkflowEvent_EventReference -// temporal.api.common.v1.Link.WorkflowEvent → Link_WorkflowEvent -func msgSchemaName(msg protoreflect.MessageDescriptor) string { - fullName := string(msg.FullName()) - pkg := string(msg.ParentFile().Package()) - if pkg != "" { - fullName = strings.TrimPrefix(fullName, pkg+".") - } - parts := strings.Split(fullName, ".") - if len(parts) > 2 { - parts = parts[len(parts)-2:] - } - return strings.Join(parts, "_") -} - -// collect adds the JSON Schema for msg and all transitively referenced messages to c.schemas. -// Marking visited before processing fields prevents infinite loops from circular references. -func (c *schemaCollector) collect(msg protoreflect.MessageDescriptor) { - name := msgSchemaName(msg) - if c.visited[name] { - return - } - c.visited[name] = true - - objNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - objNode.Content = append(objNode.Content, scalarNode("type"), scalarNode("object")) - - fields := msg.Fields() - if fields.Len() > 0 { - propsNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - for i := 0; i < fields.Len(); i++ { - field := fields.Get(i) - propsNode.Content = append(propsNode.Content, - scalarNode(field.JSONName()), - c.fieldNode(field), - ) - } - objNode.Content = append(objNode.Content, scalarNode("properties"), propsNode) - } - - c.schemas[name] = objNode -} - -// fieldNode returns the JSON Schema node for a single proto field, handling map, -// repeated (list), and singular cardinalities. -func (c *schemaCollector) fieldNode(field protoreflect.FieldDescriptor) *yaml.Node { - if field.IsMap() { - // map → {type: object, additionalProperties: } - valueField := field.Message().Fields().ByName("value") - node := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - node.Content = append(node.Content, - scalarNode("type"), - scalarNode("object"), - scalarNode("additionalProperties"), - c.kindNode(valueField), - ) - return node - } - item := c.kindNode(field) - if field.IsList() { - // repeated T → {type: array, items: } - node := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - node.Content = append(node.Content, - scalarNode("type"), - scalarNode("array"), - scalarNode("items"), - item, - ) - return node - } - return item -} - -// kindNode returns the JSON Schema for the base (scalar/message/enum) type of a field, -// ignoring any repeated/map cardinality wrapping. -func (c *schemaCollector) kindNode(field protoreflect.FieldDescriptor) *yaml.Node { - switch field.Kind() { - case protoreflect.BoolKind: - return typeNode("boolean") - case protoreflect.StringKind: - return typeNode("string") - case protoreflect.BytesKind: - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("string"), - scalarNode("format"), scalarNode("byte"), - ) - return n - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("integer"), - scalarNode("format"), scalarNode("int32"), - ) - return n - case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("integer"), - scalarNode("format"), scalarNode("uint32"), - ) - return n - case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind, - protoreflect.Uint64Kind, protoreflect.Fixed64Kind: - // protojson encodes 64-bit integers as decimal strings to avoid JS precision loss. - return typeNode("string") - case protoreflect.FloatKind: - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("number"), - scalarNode("format"), scalarNode("float"), - ) - return n - case protoreflect.DoubleKind: - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("number"), - scalarNode("format"), scalarNode("double"), - ) - return n - case protoreflect.EnumKind: - return enumNode(field.Enum()) - case protoreflect.MessageKind, protoreflect.GroupKind: - return c.msgRefNode(field.Message()) - } - return typeNode("object") -} - -// msgRefNode returns an inline schema for well-known proto types, or a $ref for all others. -// It also triggers recursive schema collection for non-well-known message types. -func (c *schemaCollector) msgRefNode(msg protoreflect.MessageDescriptor) *yaml.Node { - switch string(msg.FullName()) { - case "google.protobuf.Duration": - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("string"), - scalarNode("pattern"), scalarNode(`^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$`), - ) - return n - case "google.protobuf.Timestamp": - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("string"), - scalarNode("format"), scalarNode("date-time"), - ) - return n - case "google.protobuf.Empty": - return typeNode("object") - case "google.protobuf.Any", - "google.protobuf.Struct", - "google.protobuf.Value": - return typeNode("object") - case "google.protobuf.ListValue": - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("array"), - scalarNode("items"), typeNode("object"), - ) - return n - case "google.protobuf.BoolValue": - return typeNode("boolean") - case "google.protobuf.StringValue": - return typeNode("string") - case "google.protobuf.BytesValue": - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("string"), - scalarNode("format"), scalarNode("byte"), - ) - return n - case "google.protobuf.Int32Value", - "google.protobuf.UInt32Value": - return typeNode("integer") - case "google.protobuf.Int64Value", - "google.protobuf.UInt64Value": - return typeNode("string") - case "google.protobuf.FloatValue": - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("number"), - scalarNode("format"), scalarNode("float"), - ) - return n - case "google.protobuf.DoubleValue": - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, - scalarNode("type"), scalarNode("number"), - scalarNode("format"), scalarNode("double"), - ) - return n - } - name := msgSchemaName(msg) - c.collect(msg) - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, scalarNode("$ref"), scalarNode("#/types/"+name)) - return n -} - -// enumNode builds a JSON Schema enum node listing all enum value names. -func enumNode(e protoreflect.EnumDescriptor) *yaml.Node { - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - seqNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} - values := e.Values() - for i := 0; i < values.Len(); i++ { - seqNode.Content = append(seqNode.Content, scalarNode(string(values.Get(i).Name()))) - } - n.Content = append(n.Content, - scalarNode("enum"), seqNode, - scalarNode("type"), scalarNode("string"), - scalarNode("format"), scalarNode("enum"), - ) - return n -} - -func typeNode(t string) *yaml.Node { - n := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - n.Content = append(n.Content, scalarNode("type"), scalarNode(t)) - return n -} - -// addTypes inserts a "types:" section into doc, positioned between the -// "nexusrpc" version header and the "services" block. Types are sorted -// alphabetically for deterministic output. -func addTypes(doc *yaml.Node, c *schemaCollector) { - root := doc.Content[0] - - names := make([]string, 0, len(c.schemas)) - for name := range c.schemas { - names = append(names, name) - } - sort.Strings(names) - - typesNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - for _, name := range names { - schema := c.schemas[name] - if refs, ok := c.protoRefs[name]; ok { - refKeys := make([]string, 0, len(refs)) - for k := range refs { - refKeys = append(refKeys, k) - } - sort.Strings(refKeys) - prefix := make([]*yaml.Node, 0, 2*len(refs)) - for _, k := range refKeys { - prefix = append(prefix, scalarNode(k), scalarNode(refs[k])) - } - schema.Content = append(prefix, schema.Content...) - } - typesNode.Content = append(typesNode.Content, scalarNode(name), schema) - } - - // root.Content layout: [nexusrpc, 1.0.0, services, {...}] - // After insert: [nexusrpc, 1.0.0, types, {...}, services, {...}] - newContent := make([]*yaml.Node, 0, len(root.Content)+2) - newContent = append(newContent, root.Content[:2]...) - newContent = append(newContent, scalarNode("types"), typesNode) - newContent = append(newContent, root.Content[2:]...) - root.Content = newContent -} - // newDoc creates a yaml.Node document with the "nexusrpc: 1.0.0" header // and an empty "services" mapping node. func newDoc() *yaml.Node { diff --git a/cmd/protoc-gen-nexus-rpc-yaml/main.go b/cmd/protoc-gen-nexus-rpc-yaml/main.go index 23c3a8e7c..31cdca92f 100644 --- a/cmd/protoc-gen-nexus-rpc-yaml/main.go +++ b/cmd/protoc-gen-nexus-rpc-yaml/main.go @@ -1,6 +1,5 @@ -// protoc-gen-nexus-rpc-yaml is a protoc plugin that generates nexus/nexus-rpc.yaml -// and nexus/nexus-rpc.langs.yaml from proto service methods annotated with -// option (nexusannotations.v1.operation).tags = "exposed". +// protoc-gen-nexus-rpc-yaml is a protoc plugin that generates nexus/temporal-proto-models-nexusrpc.yaml +// from proto service methods annotated with option (nexusannotations.v1.operation).tags = "exposed". package main import ( diff --git a/nexus/temporal-json-schema-models-nexusrpc.yaml b/nexus/temporal-json-schema-models-nexusrpc.yaml deleted file mode 100644 index 924e448af..000000000 --- a/nexus/temporal-json-schema-models-nexusrpc.yaml +++ /dev/null @@ -1,445 +0,0 @@ -nexusrpc: 1.0.0 -types: - Deployment: - type: object - properties: - seriesName: - type: string - buildId: - type: string - Header: - type: object - properties: - fields: - type: object - additionalProperties: - $ref: '#/types/Payload' - Link: - type: object - properties: - workflowEvent: - $ref: '#/types/Link_WorkflowEvent' - batchJob: - $ref: '#/types/Link_BatchJob' - activity: - $ref: '#/types/Link_Activity' - Link_Activity: - type: object - properties: - namespace: - type: string - activityId: - type: string - runId: - type: string - Link_BatchJob: - type: object - properties: - jobId: - type: string - Link_WorkflowEvent: - type: object - properties: - namespace: - type: string - workflowId: - type: string - runId: - type: string - eventRef: - $ref: '#/types/WorkflowEvent_EventReference' - requestIdRef: - $ref: '#/types/WorkflowEvent_RequestIdReference' - Memo: - type: object - properties: - fields: - type: object - additionalProperties: - $ref: '#/types/Payload' - Payload: - type: object - properties: - metadata: - type: object - additionalProperties: - type: string - format: byte - data: - type: string - format: byte - externalPayloads: - type: array - items: - $ref: '#/types/Payload_ExternalPayloadDetails' - Payload_ExternalPayloadDetails: - type: object - properties: - sizeBytes: - type: string - Payloads: - type: object - properties: - payloads: - type: array - items: - $ref: '#/types/Payload' - Priority: - type: object - properties: - priorityKey: - type: integer - format: int32 - fairnessKey: - type: string - fairnessWeight: - type: number - format: float - RetryPolicy: - type: object - properties: - initialInterval: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - backoffCoefficient: - type: number - format: double - maximumInterval: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - maximumAttempts: - type: integer - format: int32 - nonRetryableErrorTypes: - type: array - items: - type: string - SearchAttributes: - type: object - properties: - indexedFields: - type: object - additionalProperties: - $ref: '#/types/Payload' - SignalWithStartWorkflowExecutionRequest: - $dotnetProtoRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionRequest - $goProtoRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionRequest - $javaProtoRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest - $pythonProtoRef: temporalio.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest - $rubyProtoRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionRequest - $typescriptProtoRef: '@temporalio/api/workflowservice/v1.SignalWithStartWorkflowExecutionRequest' - type: object - properties: - namespace: - type: string - workflowId: - type: string - workflowType: - $ref: '#/types/WorkflowType' - taskQueue: - $ref: '#/types/TaskQueue' - input: - $ref: '#/types/Payloads' - workflowExecutionTimeout: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - workflowRunTimeout: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - workflowTaskTimeout: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - identity: - type: string - requestId: - type: string - workflowIdReusePolicy: - enum: - - WORKFLOW_ID_REUSE_POLICY_UNSPECIFIED - - WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE - - WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY - - WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE - - WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING - type: string - format: enum - workflowIdConflictPolicy: - enum: - - WORKFLOW_ID_CONFLICT_POLICY_UNSPECIFIED - - WORKFLOW_ID_CONFLICT_POLICY_FAIL - - WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING - - WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING - type: string - format: enum - signalName: - type: string - signalInput: - $ref: '#/types/Payloads' - control: - type: string - retryPolicy: - $ref: '#/types/RetryPolicy' - cronSchedule: - type: string - memo: - $ref: '#/types/Memo' - searchAttributes: - $ref: '#/types/SearchAttributes' - header: - $ref: '#/types/Header' - workflowStartDelay: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - userMetadata: - $ref: '#/types/UserMetadata' - links: - type: array - items: - $ref: '#/types/Link' - versioningOverride: - $ref: '#/types/VersioningOverride' - priority: - $ref: '#/types/Priority' - timeSkippingConfig: - $ref: '#/types/TimeSkippingConfig' - SignalWithStartWorkflowExecutionResponse: - $dotnetProtoRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionResponse - $goProtoRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse - $javaProtoRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse - $pythonProtoRef: temporalio.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse - $rubyProtoRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionResponse - $typescriptProtoRef: '@temporalio/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse' - type: object - properties: - runId: - type: string - started: - type: boolean - signalLink: - $ref: '#/types/Link' - TaskQueue: - type: object - properties: - name: - type: string - kind: - enum: - - TASK_QUEUE_KIND_UNSPECIFIED - - TASK_QUEUE_KIND_NORMAL - - TASK_QUEUE_KIND_STICKY - - TASK_QUEUE_KIND_WORKER_COMMANDS - type: string - format: enum - normalName: - type: string - TimeSkippingConfig: - type: object - properties: - enabled: - type: boolean - disablePropagation: - type: boolean - maxSkippedDuration: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - maxElapsedDuration: - type: string - pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ - maxTargetTime: - type: string - format: date-time - UserMetadata: - type: object - properties: - summary: - $ref: '#/types/Payload' - details: - $ref: '#/types/Payload' - VersioningOverride: - type: object - properties: - pinned: - $ref: '#/types/VersioningOverride_PinnedOverride' - autoUpgrade: - type: boolean - behavior: - enum: - - VERSIONING_BEHAVIOR_UNSPECIFIED - - VERSIONING_BEHAVIOR_PINNED - - VERSIONING_BEHAVIOR_AUTO_UPGRADE - type: string - format: enum - deployment: - $ref: '#/types/Deployment' - pinnedVersion: - type: string - VersioningOverride_PinnedOverride: - type: object - properties: - behavior: - enum: - - PINNED_OVERRIDE_BEHAVIOR_UNSPECIFIED - - PINNED_OVERRIDE_BEHAVIOR_PINNED - type: string - format: enum - version: - $ref: '#/types/WorkerDeploymentVersion' - WorkerDeploymentVersion: - type: object - properties: - buildId: - type: string - deploymentName: - type: string - WorkflowEvent_EventReference: - type: object - properties: - eventId: - type: string - eventType: - enum: - - EVENT_TYPE_UNSPECIFIED - - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED - - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED - - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT - - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED - - EVENT_TYPE_WORKFLOW_TASK_STARTED - - EVENT_TYPE_WORKFLOW_TASK_COMPLETED - - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT - - EVENT_TYPE_WORKFLOW_TASK_FAILED - - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED - - EVENT_TYPE_ACTIVITY_TASK_STARTED - - EVENT_TYPE_ACTIVITY_TASK_COMPLETED - - EVENT_TYPE_ACTIVITY_TASK_FAILED - - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT - - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED - - EVENT_TYPE_ACTIVITY_TASK_CANCELED - - EVENT_TYPE_TIMER_STARTED - - EVENT_TYPE_TIMER_FIRED - - EVENT_TYPE_TIMER_CANCELED - - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED - - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED - - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED - - EVENT_TYPE_MARKER_RECORDED - - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED - - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED - - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW - - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED - - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED - - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED - - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY - - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY - - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED - - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED - - EVENT_TYPE_NEXUS_OPERATION_STARTED - - EVENT_TYPE_NEXUS_OPERATION_COMPLETED - - EVENT_TYPE_NEXUS_OPERATION_FAILED - - EVENT_TYPE_NEXUS_OPERATION_CANCELED - - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED - - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED - - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED - - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED - type: string - format: enum - WorkflowEvent_RequestIdReference: - type: object - properties: - requestId: - type: string - eventType: - enum: - - EVENT_TYPE_UNSPECIFIED - - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED - - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED - - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT - - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED - - EVENT_TYPE_WORKFLOW_TASK_STARTED - - EVENT_TYPE_WORKFLOW_TASK_COMPLETED - - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT - - EVENT_TYPE_WORKFLOW_TASK_FAILED - - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED - - EVENT_TYPE_ACTIVITY_TASK_STARTED - - EVENT_TYPE_ACTIVITY_TASK_COMPLETED - - EVENT_TYPE_ACTIVITY_TASK_FAILED - - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT - - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED - - EVENT_TYPE_ACTIVITY_TASK_CANCELED - - EVENT_TYPE_TIMER_STARTED - - EVENT_TYPE_TIMER_FIRED - - EVENT_TYPE_TIMER_CANCELED - - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED - - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED - - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED - - EVENT_TYPE_MARKER_RECORDED - - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED - - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED - - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW - - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT - - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED - - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED - - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED - - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED - - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED - - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED - - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY - - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY - - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED - - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED - - EVENT_TYPE_NEXUS_OPERATION_STARTED - - EVENT_TYPE_NEXUS_OPERATION_COMPLETED - - EVENT_TYPE_NEXUS_OPERATION_FAILED - - EVENT_TYPE_NEXUS_OPERATION_CANCELED - - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED - - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED - - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED - - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED - - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED - type: string - format: enum - WorkflowType: - type: object - properties: - name: - type: string -services: - WorkflowService: - operations: - SignalWithStartWorkflowExecution: - input: - $ref: '#/types/SignalWithStartWorkflowExecutionRequest' - output: - $ref: '#/types/SignalWithStartWorkflowExecutionResponse' From 6e518a77cde48234d361aa6c8b6f3b489fd4fcae Mon Sep 17 00:00:00 2001 From: Sean Kane Date: Mon, 27 Apr 2026 13:37:32 -0400 Subject: [PATCH 22/22] remove nexusnnotations sync from make proto --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index aa3a5f11f..ea42652e9 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ ci-build: install proto http-api-docs install: grpc-install api-linter-install buf-install # Run all linters and compile proto files. -proto: sync-nexus-annotations grpc http-api-docs nexus-rpc-yaml +proto: grpc http-api-docs nexus-rpc-yaml ######################################################################## ##### Variables ######