diff --git a/.gitignore b/.gitignore index 630e0fa..bc80243 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ bazel-* .bazelrc.user .idea/ .ijwb/ +node_modules/ # Ignore until it is more stable MODULE.bazel.lock diff --git a/.prettierignore b/.prettierignore index 2e117bf..57efff1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ docs/*.md +examples/**/*_pb.d.ts diff --git a/examples/.bazelignore b/examples/.bazelignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/examples/.bazelignore @@ -0,0 +1 @@ +node_modules diff --git a/examples/.bazelrc b/examples/.bazelrc index 06d1d1b..6c89af4 100644 --- a/examples/.bazelrc +++ b/examples/.bazelrc @@ -4,3 +4,5 @@ common --@aspect_rules_py//py:interpreter_version=3.9.18 # Force rules_go to disable CGO even though we have a (fake) C++ toolchain registered. common --host_platform=//tools:no_cgo_host_platform +common --@aspect_rules_ts//ts:skipLibCheck=always +common --@aspect_rules_ts//ts:default_to_tsc_transpiler diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index 5eda38d..20bd431 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -1,30 +1,19 @@ -load("@rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") -load("@protobuf//bazel:py_proto_library.bzl", "py_proto_library") +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config") +load("@npm//:defs.bzl", "npm_link_all_packages") package(default_visibility = ["//visibility:public"]) -proto_library( - name = "foo_proto", - srcs = ["foo.proto"], - deps = ["@com_google_protobuf//:any_proto"], +copy_to_bin( + name = "package_json", + srcs = ["package.json"], ) -py_proto_library( - name = "foo_py_proto", - deps = [":foo_proto"], -) - -# Broken by https://github.com/protocolbuffers/protobuf/pull/19679 -# which causes building C++ code from source. -# TODO: re-enable once protobuf honors the toolchain -# java_proto_library( -# name = "foo_java_proto", -# deps = [":foo_proto"], -# ) +# Link all direct dependencies in /package.json to +# bazel-bin/node_modules +npm_link_all_packages(name = "node_modules") -go_proto_library( - name = "foo_go_proto", - importpath = "example.com/foo_proto", - proto = ":foo_proto", +ts_config( + name = "tsconfig", + src = "tsconfig.json", ) diff --git a/examples/MODULE.bazel b/examples/MODULE.bazel index a7180ec..c70cebd 100644 --- a/examples/MODULE.bazel +++ b/examples/MODULE.bazel @@ -1,11 +1,15 @@ bazel_dep(name = "toolchains_protoc", version = "0.0.0") bazel_dep(name = "aspect_bazel_lib", version = "2.11.0") +bazel_dep(name = "aspect_rules_js", version = "2.2.0") bazel_dep(name = "aspect_rules_py", version = "1.3.2") +bazel_dep(name = "aspect_rules_ts", version = "3.5.1") bazel_dep(name = "platforms", version = "0.0.11") bazel_dep(name = "protobuf", version = "29.3") bazel_dep(name = "rules_java", version = "8.6.3") bazel_dep(name = "rules_proto", version = "7.1.0") bazel_dep(name = "rules_python", version = "1.2.0-rc0") +bazel_dep(name = "rules_rust", version = "0.59.1") +bazel_dep(name = "rules_rust_prost", version = "0.59.1") bazel_dep(name = "rules_go", version = "0.53.0") bazel_dep(name = "rules_uv", version = "0.56.0") @@ -72,3 +76,97 @@ http_jar( sha256 = "0532ad1024d62361561acaedb974d7d16889e7670b36e23e9321dd6b9d334ef9", urls = ["https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/4.27.0-RC3/protobuf-java-4.27.0-RC3.jar"], ) + +####### RUST ########## +RUST_EDITION = "2021" + +RUST_VERSION = "1.79.0" + +rust = use_extension("@rules_rust//rust:extensions.bzl", "rust") +rust.toolchain( + edition = RUST_EDITION, + versions = [RUST_VERSION], +) +use_repo(rust, "rust_toolchains") + +register_toolchains("@rust_toolchains//:all") + +# Proto toolchain + +crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate") + +# protobuf / gRPC dependencies +crate.spec( + package = "prost", + version = "0.13.1", +) +crate.spec( + default_features = False, + package = "prost-types", + version = "0.13.1", +) +crate.spec( + features = ["transport"], + package = "tonic", + version = "0.12.1", +) +crate.spec( + package = "tonic-build", + version = "0.12.1", +) +crate.spec( + package = "protoc-gen-prost", + version = "0.4.0", +) +crate.annotation( + crate = "protoc-gen-prost", + gen_binaries = ["protoc-gen-prost"], +) +crate.spec( + package = "protoc-gen-tonic", + version = "0.4.0", +) +crate.annotation( + crate = "protoc-gen-tonic", + gen_binaries = ["protoc-gen-tonic"], +) +crate.spec( + default_features = False, + features = [ + "macros", + "net", + "rt-multi-thread", + "signal", + ], + package = "tokio", + version = "1.38", +) +crate.from_specs() +use_repo(crate, "crates") + +####### TYPESCRIPT ########## +npm = use_extension( + "@aspect_rules_js//npm:extensions.bzl", + "npm", + dev_dependency = True, +) + +pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm") + +npm.npm_translate_lock( + name = "npm", + pnpm_lock = "//:pnpm-lock.yaml", +) +use_repo(npm, "npm") + +use_repo(pnpm, "pnpm") + +rules_ts_ext = use_extension( + "@aspect_rules_ts//ts:extensions.bzl", + "ext", + dev_dependency = True, +) +rules_ts_ext.deps( + ts_version_from = "//:package.json", +) +use_repo(rules_ts_ext, "npm_typescript") diff --git a/examples/WORKSPACE.bazel b/examples/WORKSPACE.bazel deleted file mode 100644 index e69de29..0000000 diff --git a/examples/foo.proto b/examples/foo.proto deleted file mode 100644 index 465255b..0000000 --- a/examples/foo.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -import "google/protobuf/any.proto"; - -option go_package = "example.com/foo_proto"; -option java_package = "proto"; - -message Foo { - string msg = 1; - repeated google.protobuf.Any details = 2; -} diff --git a/examples/go/BUILD b/examples/go/BUILD index db2b107..05689b6 100644 --- a/examples/go/BUILD +++ b/examples/go/BUILD @@ -1,7 +1,7 @@ load("@rules_go//go:def.bzl", "go_test") go_test( - name = "foo_proto_test", - srcs = ["foo_proto_test.go"], - deps = ["//:foo_go_proto"], + name = "greeter_proto_test", + srcs = ["greeter_proto_test.go"], + deps = ["//proto:greeter_go_proto"], ) diff --git a/examples/go/foo_proto_test.go b/examples/go/foo_proto_test.go deleted file mode 100644 index 114188a..0000000 --- a/examples/go/foo_proto_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package proto_test - -import ( - "testing" - - "example.com/foo_proto" -) - -func TestFoo(t *testing.T) { - msg := &foo_proto.Foo{ - Msg: "hello world", - } - if msg.Msg != "hello world" { - t.Fail() - } -} diff --git a/examples/go/greeter_proto_test.go b/examples/go/greeter_proto_test.go new file mode 100644 index 0000000..691d6c0 --- /dev/null +++ b/examples/go/greeter_proto_test.go @@ -0,0 +1,16 @@ +package proto_test + +import ( + "testing" + + "example.com/greeter_proto" +) + +func TestFoo(t *testing.T) { + msg := &greeter_proto.HelloReply{ + Message: "hello world", + } + if msg.Message != "hello world" { + t.Fail() + } +} diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000..3597763 --- /dev/null +++ b/examples/package.json @@ -0,0 +1,15 @@ +{ + "dependencies": { + "@bufbuild/protobuf": "^2.2.4", + "@connectrpc/connect-node": "2.0.2", + "@connectrpc/connect-fastify": "~2.0.2", + "fastify": "~5.2.1" + }, + "devDependencies": { + "@bufbuild/protoc-gen-es": "~2.2.4", + "@connectrpc/connect": "~2.0.2", + "typescript": "5.7.2", + "@types/node": "~22.13.10" + }, + "type": "module" +} diff --git a/examples/pnpm-lock.yaml b/examples/pnpm-lock.yaml new file mode 100644 index 0000000..f2b58ab --- /dev/null +++ b/examples/pnpm-lock.yaml @@ -0,0 +1,606 @@ +lockfileVersion: "6.0" + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + "@bufbuild/protobuf": + specifier: ^2.2.4 + version: 2.2.4 + "@connectrpc/connect-fastify": + specifier: ~2.0.2 + version: 2.0.2(@bufbuild/protobuf@2.2.4)(@connectrpc/connect-node@2.0.2)(@connectrpc/connect@2.0.2)(fastify@5.2.1) + "@connectrpc/connect-node": + specifier: 2.0.2 + version: 2.0.2(@bufbuild/protobuf@2.2.4)(@connectrpc/connect@2.0.2) + fastify: + specifier: ~5.2.1 + version: 5.2.1 + +devDependencies: + "@bufbuild/protoc-gen-es": + specifier: ~2.2.4 + version: 2.2.4(@bufbuild/protobuf@2.2.4) + "@connectrpc/connect": + specifier: ~2.0.2 + version: 2.0.2(@bufbuild/protobuf@2.2.4) + "@types/node": + specifier: ~22.13.10 + version: 22.13.10 + typescript: + specifier: 5.7.2 + version: 5.7.2 + +packages: + /@bufbuild/protobuf@2.2.4: + resolution: + { + integrity: sha512-P9xQgtMh71TA7tHTnbDe68zcI+TPnkyyfBIhGaUr4iUEIXN7yI01DyjmmdEwXTk5OlISBJYkoxCVj2dwmHqIkA==, + } + + /@bufbuild/protoc-gen-es@2.2.4(@bufbuild/protobuf@2.2.4): + resolution: + { + integrity: sha512-s8hCpjYBCIKTFGfoEdnxIxgZkp3tBtFLz96J82TKNtrOATR5VBj3EPp53/rAG7+I7uguPfcDslO0EZxlzLVtdA==, + } + engines: { node: ">=14" } + hasBin: true + peerDependencies: + "@bufbuild/protobuf": 2.2.4 + peerDependenciesMeta: + "@bufbuild/protobuf": + optional: true + dependencies: + "@bufbuild/protobuf": 2.2.4 + "@bufbuild/protoplugin": 2.2.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@bufbuild/protoplugin@2.2.4: + resolution: + { + integrity: sha512-OGoc31DokbTu6Ev8808oWPPMgBKLdEBTheMYvRK//2jI7E7oSMxPBlFeRTRiRUfhbQ2TvW20SgJwTLDUsNe8Iw==, + } + dependencies: + "@bufbuild/protobuf": 2.2.4 + "@typescript/vfs": 1.6.1(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@connectrpc/connect-fastify@2.0.2(@bufbuild/protobuf@2.2.4)(@connectrpc/connect-node@2.0.2)(@connectrpc/connect@2.0.2)(fastify@5.2.1): + resolution: + { + integrity: sha512-rOobWfWc09+Ws4x+tfZFd12UBezMInq+V5chqbgGuGgajZXyEPRfu8ePo0IiKltWptOq7oPAyaEbadpgcZsnBg==, + } + engines: { node: ">=18.14.1" } + peerDependencies: + "@bufbuild/protobuf": ^2.2.0 + "@connectrpc/connect": 2.0.2 + "@connectrpc/connect-node": 2.0.2 + fastify: ^4.22.1 || ^5.1.0 + dependencies: + "@bufbuild/protobuf": 2.2.4 + "@connectrpc/connect": 2.0.2(@bufbuild/protobuf@2.2.4) + "@connectrpc/connect-node": 2.0.2(@bufbuild/protobuf@2.2.4)(@connectrpc/connect@2.0.2) + fastify: 5.2.1 + dev: false + + /@connectrpc/connect-node@2.0.2(@bufbuild/protobuf@2.2.4)(@connectrpc/connect@2.0.2): + resolution: + { + integrity: sha512-33Ut3SRkb6SugpwVCtXXRvUrOdtiyG6z6d5+eijBOLOI75sw1tDCwcs0o/9WL3rUj1M08dLUrPmJB47fjpv6EA==, + } + engines: { node: ">=18.14.1" } + peerDependencies: + "@bufbuild/protobuf": ^2.2.0 + "@connectrpc/connect": 2.0.2 + dependencies: + "@bufbuild/protobuf": 2.2.4 + "@connectrpc/connect": 2.0.2(@bufbuild/protobuf@2.2.4) + dev: false + + /@connectrpc/connect@2.0.2(@bufbuild/protobuf@2.2.4): + resolution: + { + integrity: sha512-xZuylIUNvNlH52e/4eQsZvY4QZyDJRtEFEDnn/yBrv5Xi5ZZI/p8X+GAHH35ucVaBvv9u7OzHZo8+tEh1EFTxA==, + } + peerDependencies: + "@bufbuild/protobuf": ^2.2.0 + dependencies: + "@bufbuild/protobuf": 2.2.4 + + /@fastify/ajv-compiler@4.0.2: + resolution: + { + integrity: sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ==, + } + dependencies: + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + fast-uri: 3.0.6 + dev: false + + /@fastify/error@4.1.0: + resolution: + { + integrity: sha512-KeFcciOr1eo/YvIXHP65S94jfEEqn1RxTRBT1aJaHxY5FK0/GDXYozsQMMWlZoHgi8i0s+YtrLsgj/JkUUjSkQ==, + } + dev: false + + /@fastify/fast-json-stringify-compiler@5.0.2: + resolution: + { + integrity: sha512-YdR7gqlLg1xZAQa+SX4sMNzQHY5pC54fu9oC5aYSUqBhyn6fkLkrdtKlpVdCNPlwuUuXA1PjFTEmvMF6ZVXVGw==, + } + dependencies: + fast-json-stringify: 6.0.1 + dev: false + + /@fastify/forwarded@3.0.0: + resolution: + { + integrity: sha512-kJExsp4JCms7ipzg7SJ3y8DwmePaELHxKYtg+tZow+k0znUTf3cb+npgyqm8+ATZOdmfgfydIebPDWM172wfyA==, + } + dev: false + + /@fastify/merge-json-schemas@0.2.1: + resolution: + { + integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==, + } + dependencies: + dequal: 2.0.3 + dev: false + + /@fastify/proxy-addr@5.0.0: + resolution: + { + integrity: sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==, + } + dependencies: + "@fastify/forwarded": 3.0.0 + ipaddr.js: 2.2.0 + dev: false + + /@types/node@22.13.10: + resolution: + { + integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==, + } + dependencies: + undici-types: 6.20.0 + dev: true + + /@typescript/vfs@1.6.1(typescript@5.4.5): + resolution: + { + integrity: sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA==, + } + peerDependencies: + typescript: "*" + dependencies: + debug: 4.4.0 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + + /abstract-logging@2.0.1: + resolution: + { + integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==, + } + dev: false + + /ajv-formats@3.0.1(ajv@8.17.1): + resolution: + { + integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==, + } + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.17.1 + dev: false + + /ajv@8.17.1: + resolution: + { + integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==, + } + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + dev: false + + /atomic-sleep@1.0.0: + resolution: + { + integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==, + } + engines: { node: ">=8.0.0" } + dev: false + + /avvio@9.1.0: + resolution: + { + integrity: sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==, + } + dependencies: + "@fastify/error": 4.1.0 + fastq: 1.19.1 + dev: false + + /cookie@1.0.2: + resolution: + { + integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==, + } + engines: { node: ">=18" } + dev: false + + /debug@4.4.0: + resolution: + { + integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==, + } + engines: { node: ">=6.0" } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /dequal@2.0.3: + resolution: + { + integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==, + } + engines: { node: ">=6" } + dev: false + + /fast-decode-uri-component@1.0.1: + resolution: + { + integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==, + } + dev: false + + /fast-deep-equal@3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + dev: false + + /fast-json-stringify@6.0.1: + resolution: + { + integrity: sha512-s7SJE83QKBZwg54dIbD5rCtzOBVD43V1ReWXXYqBgwCwHLYAAT0RQc/FmrQglXqWPpz6omtryJQOau5jI4Nrvg==, + } + dependencies: + "@fastify/merge-json-schemas": 0.2.1 + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + fast-uri: 3.0.6 + json-schema-ref-resolver: 2.0.1 + rfdc: 1.4.1 + dev: false + + /fast-querystring@1.1.2: + resolution: + { + integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==, + } + dependencies: + fast-decode-uri-component: 1.0.1 + dev: false + + /fast-redact@3.5.0: + resolution: + { + integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==, + } + engines: { node: ">=6" } + dev: false + + /fast-uri@3.0.6: + resolution: + { + integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==, + } + dev: false + + /fastify@5.2.1: + resolution: + { + integrity: sha512-rslrNBF67eg8/Gyn7P2URV8/6pz8kSAscFL4EThZJ8JBMaXacVdVE4hmUcnPNKERl5o/xTiBSLfdowBRhVF1WA==, + } + dependencies: + "@fastify/ajv-compiler": 4.0.2 + "@fastify/error": 4.1.0 + "@fastify/fast-json-stringify-compiler": 5.0.2 + "@fastify/proxy-addr": 5.0.0 + abstract-logging: 2.0.1 + avvio: 9.1.0 + fast-json-stringify: 6.0.1 + find-my-way: 9.2.0 + light-my-request: 6.6.0 + pino: 9.6.0 + process-warning: 4.0.1 + rfdc: 1.4.1 + secure-json-parse: 3.0.2 + semver: 7.7.1 + toad-cache: 3.7.0 + dev: false + + /fastq@1.19.1: + resolution: + { + integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==, + } + dependencies: + reusify: 1.1.0 + dev: false + + /find-my-way@9.2.0: + resolution: + { + integrity: sha512-d3uCir8Hmg7W1Ywp8nKf2lJJYU9Nwinvo+1D39Dn09nz65UKXIxUh7j7K8zeWhxqe1WrkS7FJyON/Q/3lPoc6w==, + } + engines: { node: ">=14" } + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 4.0.1 + dev: false + + /ipaddr.js@2.2.0: + resolution: + { + integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==, + } + engines: { node: ">= 10" } + dev: false + + /json-schema-ref-resolver@2.0.1: + resolution: + { + integrity: sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q==, + } + dependencies: + dequal: 2.0.3 + dev: false + + /json-schema-traverse@1.0.0: + resolution: + { + integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, + } + dev: false + + /light-my-request@6.6.0: + resolution: + { + integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==, + } + dependencies: + cookie: 1.0.2 + process-warning: 4.0.1 + set-cookie-parser: 2.7.1 + dev: false + + /ms@2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + dev: true + + /on-exit-leak-free@2.1.2: + resolution: + { + integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==, + } + engines: { node: ">=14.0.0" } + dev: false + + /pino-abstract-transport@2.0.0: + resolution: + { + integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==, + } + dependencies: + split2: 4.2.0 + dev: false + + /pino-std-serializers@7.0.0: + resolution: + { + integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==, + } + dev: false + + /pino@9.6.0: + resolution: + { + integrity: sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==, + } + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 4.0.1 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + dev: false + + /process-warning@4.0.1: + resolution: + { + integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==, + } + dev: false + + /quick-format-unescaped@4.0.4: + resolution: + { + integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==, + } + dev: false + + /real-require@0.2.0: + resolution: + { + integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==, + } + engines: { node: ">= 12.13.0" } + dev: false + + /require-from-string@2.0.2: + resolution: + { + integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, + } + engines: { node: ">=0.10.0" } + dev: false + + /ret@0.5.0: + resolution: + { + integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==, + } + engines: { node: ">=10" } + dev: false + + /reusify@1.1.0: + resolution: + { + integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, + } + engines: { iojs: ">=1.0.0", node: ">=0.10.0" } + dev: false + + /rfdc@1.4.1: + resolution: + { + integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==, + } + dev: false + + /safe-regex2@4.0.1: + resolution: + { + integrity: sha512-goqsB+bSlOmVX+CiFX2PFc1OV88j5jvBqIM+DgqrucHnUguAUNtiNOs+aTadq2NqsLQ+TQ3UEVG3gtSFcdlkCg==, + } + dependencies: + ret: 0.5.0 + dev: false + + /safe-stable-stringify@2.5.0: + resolution: + { + integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==, + } + engines: { node: ">=10" } + dev: false + + /secure-json-parse@3.0.2: + resolution: + { + integrity: sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==, + } + dev: false + + /semver@7.7.1: + resolution: + { + integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==, + } + engines: { node: ">=10" } + hasBin: true + dev: false + + /set-cookie-parser@2.7.1: + resolution: + { + integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==, + } + dev: false + + /sonic-boom@4.2.0: + resolution: + { + integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==, + } + dependencies: + atomic-sleep: 1.0.0 + dev: false + + /split2@4.2.0: + resolution: + { + integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==, + } + engines: { node: ">= 10.x" } + dev: false + + /thread-stream@3.1.0: + resolution: + { + integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==, + } + dependencies: + real-require: 0.2.0 + dev: false + + /toad-cache@3.7.0: + resolution: + { + integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==, + } + engines: { node: ">=12" } + dev: false + + /typescript@5.4.5: + resolution: + { + integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==, + } + engines: { node: ">=14.17" } + hasBin: true + dev: true + + /typescript@5.7.2: + resolution: + { + integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==, + } + engines: { node: ">=14.17" } + hasBin: true + dev: true + + /undici-types@6.20.0: + resolution: + { + integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==, + } + dev: true diff --git a/examples/proto/BUILD.bazel b/examples/proto/BUILD.bazel new file mode 100644 index 0000000..88c206c --- /dev/null +++ b/examples/proto/BUILD.bazel @@ -0,0 +1,48 @@ +load("@aspect_rules_ts//ts:proto.bzl", "ts_proto_library") +load("@rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@rules_rust_prost//:defs.bzl", "rust_prost_library") +load("@protobuf//bazel:py_proto_library.bzl", "py_proto_library") + +package(default_visibility = ["//visibility:public"]) + +proto_library( + name = "greeter_proto", + srcs = ["greeter.proto"], + deps = ["@com_google_protobuf//:any_proto"], +) + +py_proto_library( + name = "greeter_py_proto", + deps = [":greeter_proto"], +) + +# Broken by https://github.com/protocolbuffers/protobuf/pull/19679 +# which causes building C++ code from source. +# TODO: re-enable once protobuf honors the toolchain +# java_proto_library( +# name = "greeter_java_proto", +# deps = [":greeter_proto"], +# ) + +go_proto_library( + name = "greeter_go_proto", + importpath = "example.com/greeter_proto", + proto = ":greeter_proto", +) + +# Generate Rust bindings from the generated proto files +# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_prost_library +rust_prost_library( + name = "greeter_rust_proto", + proto = ":greeter_proto", + visibility = ["//visibility:public"], +) + +ts_proto_library( + name = "greeter_ts_proto", + gen_connect_es = False, + node_modules = "//:node_modules", + proto = ":greeter_proto", + proto_srcs = ["greeter.proto"], # to copy greeter.d.ts back to the source tree +) diff --git a/examples/proto/greeter.proto b/examples/proto/greeter.proto new file mode 100644 index 0000000..c2c6d1c --- /dev/null +++ b/examples/proto/greeter.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +// https://github.com/hyperium/tonic/blob/master/examples/proto/helloworld/helloworld.proto +package proto; +option go_package = "example.com/greeter_proto"; +option java_package = "proto"; + +import "google/protobuf/any.proto"; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello(HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; + repeated google.protobuf.Any details = 2; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/examples/proto/greeter_pb.d.ts b/examples/proto/greeter_pb.d.ts new file mode 100644 index 0000000..67922cd --- /dev/null +++ b/examples/proto/greeter_pb.d.ts @@ -0,0 +1,64 @@ +// @generated by protoc-gen-es v2.2.4 with parameter "keep_empty_files=true,target=js+dts" +// @generated from file proto/greeter.proto (package proto, syntax proto3) +/* eslint-disable */ + +import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1"; +import type { Message } from "@bufbuild/protobuf"; +import type { Any } from "@bufbuild/protobuf/wkt"; + +/** + * Describes the file proto/greeter.proto. + */ +export declare const file_proto_greeter: GenFile; + +/** + * @generated from message proto.HelloRequest + */ +export declare type HelloRequest = Message<"proto.HelloRequest"> & { + /** + * @generated from field: string name = 1; + */ + name: string; + + /** + * @generated from field: repeated google.protobuf.Any details = 2; + */ + details: Any[]; +}; + +/** + * Describes the message proto.HelloRequest. + * Use `create(HelloRequestSchema)` to create a new message. + */ +export declare const HelloRequestSchema: GenMessage; + +/** + * @generated from message proto.HelloReply + */ +export declare type HelloReply = Message<"proto.HelloReply"> & { + /** + * @generated from field: string message = 1; + */ + message: string; +}; + +/** + * Describes the message proto.HelloReply. + * Use `create(HelloReplySchema)` to create a new message. + */ +export declare const HelloReplySchema: GenMessage; + +/** + * @generated from service proto.Greeter + */ +export declare const Greeter: GenService<{ + /** + * @generated from rpc proto.Greeter.SayHello + */ + sayHello: { + methodKind: "unary"; + input: typeof HelloRequestSchema; + output: typeof HelloReplySchema; + }, +}>; + diff --git a/examples/proto/src/lib.rs b/examples/proto/src/lib.rs new file mode 100644 index 0000000..860d77e --- /dev/null +++ b/examples/proto/src/lib.rs @@ -0,0 +1,3 @@ +pub mod proto { + tonic::include_proto!("proto"); +} diff --git a/examples/python/BUILD b/examples/python/BUILD index 9529879..34becda 100644 --- a/examples/python/BUILD +++ b/examples/python/BUILD @@ -3,5 +3,5 @@ load("@rules_python//python:defs.bzl", "py_test") py_test( name = "message_test", srcs = ["message_test.py"], - deps = ["//:foo_py_proto"], + deps = ["//proto:greeter_py_proto"], ) diff --git a/examples/python/message_test.py b/examples/python/message_test.py index 0ea0782..2e03b51 100644 --- a/examples/python/message_test.py +++ b/examples/python/message_test.py @@ -1,12 +1,12 @@ import sys import unittest -from _main import foo_pb2 +from proto import greeter_pb2 class TestCase(unittest.TestCase): def test_message(self): - got = foo_pb2.Foo( - msg = "hello world", + got = greeter_pb2.HelloReply( + message = "hello world", ) self.assertIsNotNone(got) diff --git a/examples/rust/client/BUILD.bazel b/examples/rust/client/BUILD.bazel new file mode 100644 index 0000000..08a422c --- /dev/null +++ b/examples/rust/client/BUILD.bazel @@ -0,0 +1,23 @@ +load("@rules_rust//rust:defs.bzl", "rust_binary") + +# Build binary +# https://bazelbuild.github.io/rules_rust/defs.html#rust_binary +rust_binary( + name = "client", + srcs = glob([ + "src/*.rs", + ]), + crate_root = "src/main.rs", + rustc_flags = [ + "-Copt-level=0", + ], + visibility = ["//visibility:public"], + deps = [ + # Internal crates + "//proto:greeter_rust_proto", + # External crates + "@crates//:prost-types", + "@crates//:tokio", + "@crates//:tonic", + ], +) diff --git a/examples/rust/client/src/main.rs b/examples/rust/client/src/main.rs new file mode 100644 index 0000000..f4949aa --- /dev/null +++ b/examples/rust/client/src/main.rs @@ -0,0 +1,29 @@ +use greeter_proto::proto::greeter_client::GreeterClient; +use greeter_proto::proto::HelloRequest; +use greeter_proto::any_proto::google::protobuf::Any; + +// https://github.com/hyperium/tonic/blob/master/examples/src/helloworld/client.rs +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut client = GreeterClient::connect("http://[::1]:5042") + .await + .expect("[Client]: Failed to connect to server."); + + let detail = Any { + type_url: "type.googleapis.com/mypackage.MyMessage".to_string(), + value: b"details".to_vec(), + }; + let request = tonic::Request::new(HelloRequest { + name: "Rust Client".into(), + details: vec![detail], + }); + + let response = client + .say_hello(request) + .await + .expect("[Client]: Failed to get a response from the server"); + + println!("RESPONSE={:?}", response); + + Ok(()) +} diff --git a/examples/rust/server/BUILD.bazel b/examples/rust/server/BUILD.bazel new file mode 100644 index 0000000..f273a90 --- /dev/null +++ b/examples/rust/server/BUILD.bazel @@ -0,0 +1,20 @@ +load("@rules_rust//rust:defs.bzl", "rust_binary") + +# Build binary +# https://bazelbuild.github.io/rules_rust/defs.html#rust_binary +rust_binary( + name = "server", + srcs = glob([ + "src/*.rs", + ]), + crate_root = "src/main.rs", + rustc_flags = ["-Copt-level=0"], + visibility = ["//visibility:public"], + deps = [ + # Internal crates + "//proto:greeter_rust_proto", + # External crates + "@crates//:tokio", + "@crates//:tonic", + ], +) diff --git a/examples/rust/server/src/main.rs b/examples/rust/server/src/main.rs new file mode 100644 index 0000000..7d22bb8 --- /dev/null +++ b/examples/rust/server/src/main.rs @@ -0,0 +1,40 @@ +use std::error::Error; + +use tonic::transport::Server; + +use greeter_proto::proto::greeter_server::GreeterServer; + +use crate::server::MyGreeter; + +mod server; +mod shutdown_utils; + +// https://github.com/hyperium/tonic/blob/master/examples/src/helloworld/server.rs +#[tokio::main] +async fn main() -> Result<(), Box> { + let addr = "[::1]:5042" + .parse() + .expect("[Server]: Failed to parse socket address"); + + let grpc_svc = GreeterServer::new(MyGreeter::new()); + + // Shutdown signal handler + let signal = shutdown_utils::signal_handler("gRPC Greeter server"); + + let grpc_server = Server::builder() + .add_service(grpc_svc) + .serve_with_shutdown(addr, signal); + + let grpc_handle = tokio::spawn(grpc_server); + + println!("GreeterServer listening on {}", addr); + match tokio::try_join!(grpc_handle) { + Ok(_) => {} + Err(e) => { + println!("[Server]: Error: Failed to start gRPC Greeter server."); + println!("[Server]: Error: {:?}", e); + } + } + + Ok(()) +} \ No newline at end of file diff --git a/examples/rust/server/src/server.rs b/examples/rust/server/src/server.rs new file mode 100644 index 0000000..4984721 --- /dev/null +++ b/examples/rust/server/src/server.rs @@ -0,0 +1,28 @@ +use tonic::{Request, Response, Status}; + +use greeter_proto::proto::greeter_server::Greeter; +use greeter_proto::proto::{HelloReply, HelloRequest}; + +#[derive(Copy, Clone)] +pub struct MyGreeter {} + +impl MyGreeter { + pub fn new() -> Self { + Self {} + } +} + +#[tonic::async_trait] +impl Greeter for MyGreeter { + async fn say_hello( + &self, + request: Request, + ) -> Result, Status> { + println!("Got a request from {:?}", request.remote_addr()); + + let reply = HelloReply { + message: format!("Hello {}!", request.into_inner().name), + }; + Ok(Response::new(reply)) + } +} diff --git a/examples/rust/server/src/shutdown_utils.rs b/examples/rust/server/src/shutdown_utils.rs new file mode 100644 index 0000000..20d60e1 --- /dev/null +++ b/examples/rust/server/src/shutdown_utils.rs @@ -0,0 +1,54 @@ +// +/// Registers a signal handler that waits for a signal that indicates a shutdown request. +// https://stackoverflow.com/questions/77585473/rust-tokio-how-to-handle-more-signals-than-just-sigint-i-e-sigquit?noredirect=1#comment136778587_77585473 +pub async fn signal_handler(svc: &str) { + wait_for_signal_impl(svc).await +} + +/// Waits for a signal that requests a graceful shutdown. Supports the following signals on unix: +/// * SIGTERM +/// * SIGINT (Ctrl-C) +/// * SIGQUIT +/// * SIGHUP +#[cfg(unix)] +async fn wait_for_signal_impl(svc: &str) { + use tokio::signal::unix::{signal, SignalKind}; + + // Docs: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html + let mut signal_terminate = signal(SignalKind::terminate()).unwrap(); + let mut signal_interrupt = signal(SignalKind::interrupt()).unwrap(); + let mut signal_quit = signal(SignalKind::quit()).unwrap(); + let mut signal_hang = signal(SignalKind::hangup()).unwrap(); + + // https://docs.rs/tokio/latest/tokio/macro.select.html + tokio::select! { + _ = signal_terminate.recv() => println!("* {svc} received SIGTERM"), + _ = signal_interrupt.recv() => println!("* {svc} received SIGINT"), + _ = signal_quit.recv() => println!("* {svc} received SIGQUIT"), + _ = signal_hang.recv() => println!(" * {svc} received SIGHUP"), + } +} + +/// Waits for a signal that requests a graceful shutdown. Supports the following signals on Windows: +/// * ctrl_c +/// * ctrl_break +/// * ctrl_close +/// * ctrl_shutdown +#[cfg(windows)] +async fn wait_for_signal_impl(svc: &str) { + use tokio::signal::windows; + + // Docs: https://learn.microsoft.com/en-us/windows/console/handlerroutine + let mut signal_c = windows::ctrl_c().unwrap(); + let mut signal_break = windows::ctrl_break().unwrap(); + let mut signal_close = windows::ctrl_close().unwrap(); + let mut signal_shutdown = windows::ctrl_shutdown().unwrap(); + + // https://docs.rs/tokio/latest/tokio/macro.select.html + tokio::select! { + _ = signal_c.recv() => println!("* {svc} received CTRL_C."), + _ = signal_break.recv() => println!("* {svc} received CTRL_BREAK."), + _ = signal_close.recv() => println!("* {svc} received CTRL_CLOSE."), + _ = signal_shutdown.recv() => println!("* {svc} received CTRL_SHUTDOWN."), + } +} diff --git a/examples/tools/BUILD.bazel b/examples/tools/BUILD.bazel index 8d490c0..a891879 100644 --- a/examples/tools/BUILD.bazel +++ b/examples/tools/BUILD.bazel @@ -1,6 +1,24 @@ load("@platforms//host:constraints.bzl", "HOST_CONSTRAINTS") +load("@rules_rust//rust:defs.bzl", "rust_library_group") load("@rules_uv//uv:pip.bzl", "pip_compile") +package(default_visibility = ["//tools/toolchains:__pkg__"]) + +rust_library_group( + name = "prost_runtime", + deps = [ + "@crates//:prost", + ], +) + +rust_library_group( + name = "tonic_runtime", + deps = [ + ":prost_runtime", + "@crates//:tonic", + ], +) + pip_compile( name = "generate_requirements_txt", requirements_in = "requirements.in", diff --git a/examples/tools/toolchains/BUILD.bazel b/examples/tools/toolchains/BUILD.bazel index 1286682..ccb0c72 100644 --- a/examples/tools/toolchains/BUILD.bazel +++ b/examples/tools/toolchains/BUILD.bazel @@ -1,12 +1,5 @@ -"""Define a non-functional cc toolchain. - -To fail-fast in cases where we are forced to compile third-party C++ code, -define a cc toolchain that doesn't work, by using 'false' as the compiler. -See https://bazel.build/tutorials/ccp-toolchain-config -""" - load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain") -load("defs.bzl", "cc_toolchain_config") +load("@rules_rust_prost//:defs.bzl", "rust_prost_toolchain") # Configure protoc to have the right arguments for generating Python stubs. # NB: the protobuf team intends to remove --python_out and instead use a protoc plugin for Python stub emit. @@ -27,29 +20,17 @@ proto_lang_toolchain( toolchain_type = "@rules_java//java/proto:toolchain_type", ) -################ -# Setup a non-functional C++ toolchain, so we're assured that no C++ compilation -# will be expected for engineers working in our repo. -# That's the critical guarantee of toolchains_protoc -filegroup(name = "empty") - -cc_toolchain_config(name = "noop_toolchain_config") - -cc_toolchain( - name = "noop_toolchain", - all_files = ":empty", - compiler_files = ":empty", - dwp_files = ":empty", - linker_files = ":empty", - objcopy_files = ":empty", - strip_files = ":empty", - supports_param_files = 0, - toolchain_config = ":noop_toolchain_config", - toolchain_identifier = "noop-toolchain", +rust_prost_toolchain( + name = "prost_toolchain_impl", + prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost", + prost_runtime = "//tools:prost_runtime", + prost_types = "@crates//:prost-types", + tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic", + tonic_runtime = "//tools:tonic_runtime", ) toolchain( - name = "cc_toolchain", - toolchain = ":noop_toolchain", - toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", + name = "prost_toolchain", + toolchain = "prost_toolchain_impl", + toolchain_type = "@rules_rust_prost//:toolchain_type", ) diff --git a/examples/tools/toolchains/defs.bzl b/examples/tools/toolchains/defs.bzl deleted file mode 100644 index 4aeee59..0000000 --- a/examples/tools/toolchains/defs.bzl +++ /dev/null @@ -1,20 +0,0 @@ -"Configure a cc toolchain to call 'false' if used." - -def _impl(ctx): - return cc_common.create_cc_toolchain_config_info( - ctx = ctx, - toolchain_identifier = "noop-toolchain", - host_system_name = "local", - target_system_name = "local", - target_cpu = "k8", - target_libc = "unknown", - compiler = "false", - abi_version = "unknown", - abi_libc_version = "unknown", - ) - -cc_toolchain_config = rule( - implementation = _impl, - attrs = {}, - provides = [CcToolchainConfigInfo], -) diff --git a/examples/tsconfig.json b/examples/tsconfig.json new file mode 100644 index 0000000..d5cb4df --- /dev/null +++ b/examples/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "lib": ["ES2018"], + "module": "ES2022", + "target": "ES2017", + "moduleResolution": "node" + } +} diff --git a/examples/typescript/client/BUILD.bazel b/examples/typescript/client/BUILD.bazel new file mode 100644 index 0000000..464ce97 --- /dev/null +++ b/examples/typescript/client/BUILD.bazel @@ -0,0 +1,21 @@ +load("@aspect_rules_js//js:defs.bzl", "js_binary") +load("@aspect_rules_ts//ts:defs.bzl", "ts_project") + +ts_project( + name = "main", + srcs = ["main.mts"], + tsconfig = "//:tsconfig", + deps = [ + "//:node_modules/@connectrpc/connect", + "//:node_modules/@connectrpc/connect-node", + "//:node_modules/@types/node", + "//:package_json", + "//proto:greeter_ts_proto", + ], +) + +js_binary( + name = "client", + data = [":main"], + entry_point = "main.mjs", +) diff --git a/examples/typescript/client/main.mts b/examples/typescript/client/main.mts new file mode 100644 index 0000000..4c8613c --- /dev/null +++ b/examples/typescript/client/main.mts @@ -0,0 +1,21 @@ +import { createClient , CallOptions} from "@connectrpc/connect"; +import { createGrpcTransport } from "@connectrpc/connect-node"; +import {Greeter} from "../../proto/greeter_pb.js"; + +const transport = createGrpcTransport({ + baseUrl: "http://localhost:5042", +}); + +async function main() { + const client = createClient(Greeter, transport); + const res = await client.sayHello({ + name: "TypeScript Client", + }, {onHeader: (headers) => { + console.log("Headers:") + for (const [name, value] of headers) { + console.log(`${name}: ${value}`); + } + }}); + console.log((res as /*todo*/any).message); +} +void main(); diff --git a/examples/typescript/server/BUILD.bazel b/examples/typescript/server/BUILD.bazel new file mode 100644 index 0000000..99559a5 --- /dev/null +++ b/examples/typescript/server/BUILD.bazel @@ -0,0 +1,25 @@ +load("@aspect_rules_js//js:defs.bzl", "js_binary") +load("@aspect_rules_ts//ts:defs.bzl", "ts_project") + +ts_project( + name = "main", + srcs = [ + "connect.mts", + "main.mts", + ], + tsconfig = "//:tsconfig", + deps = [ + "//:node_modules/@connectrpc/connect", + "//:node_modules/@connectrpc/connect-fastify", + "//:node_modules/@types/node", + "//:node_modules/fastify", + "//:package_json", + "//proto:greeter_ts_proto", + ], +) + +js_binary( + name = "server", + data = [":main"], + entry_point = "main.mjs", +) diff --git a/examples/typescript/server/connect.mts b/examples/typescript/server/connect.mts new file mode 100644 index 0000000..23e63eb --- /dev/null +++ b/examples/typescript/server/connect.mts @@ -0,0 +1,11 @@ +import { ConnectRouter, HandlerContext } from "@connectrpc/connect"; +import { Greeter, HelloRequest } from "../../proto/greeter_pb.js"; + +export default (router: ConnectRouter) => + router.service(Greeter, { + async sayHello(req: HelloRequest, context: HandlerContext) { + return { + message: `Hello ${req.name}!`, + }; + } + }); diff --git a/examples/typescript/server/main.mts b/examples/typescript/server/main.mts new file mode 100644 index 0000000..ecf9c0f --- /dev/null +++ b/examples/typescript/server/main.mts @@ -0,0 +1,19 @@ +import { fastify } from "fastify"; +import { fastifyConnectPlugin } from "@connectrpc/connect-fastify"; +import routes from "./connect.mjs"; +import { readFileSync } from "fs"; + +// See https://connectrpc.com/docs/node/getting-started +async function main() { + const server = fastify({http2: true}); + await server.register(fastifyConnectPlugin, {routes}); + server.get("/", (_, reply) => { + reply.type("text/plain"); + reply.send("Hello World!"); + }); + await server.listen({ host: "localhost", port: 5042 }); + console.log("server is listening at", server.addresses()); +} +// You can remove the main() wrapper if you set type: module in your package.json, +// and update your tsconfig.json with target: es2017 and module: es2022. +void main();