From 3eb081d07997578fc27d68436e708ce2e61b1b08 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Mon, 17 Mar 2025 21:46:16 -0700 Subject: [PATCH 1/6] feat: demonstrate rust client/server --- examples/BUILD.bazel | 30 ---------- examples/MODULE.bazel | 69 ++++++++++++++++++++++ examples/WORKSPACE.bazel | 0 examples/foo.proto | 11 ---- examples/go/BUILD | 6 +- examples/go/foo_proto_test.go | 16 ----- examples/go/greeter_proto_test.go | 16 +++++ examples/proto/BUILD.bazel | 39 ++++++++++++ examples/proto/greeter.proto | 25 ++++++++ examples/proto/src/lib.rs | 3 + examples/python/BUILD | 2 +- examples/python/message_test.py | 6 +- examples/rust/client/BUILD.bazel | 23 ++++++++ examples/rust/client/src/main.rs | 29 +++++++++ examples/rust/server/BUILD.bazel | 20 +++++++ examples/rust/server/src/main.rs | 40 +++++++++++++ examples/rust/server/src/server.rs | 28 +++++++++ examples/rust/server/src/shutdown_utils.rs | 54 +++++++++++++++++ examples/tools/toolchains/BUILD.bazel | 42 +++++++++++-- 19 files changed, 390 insertions(+), 69 deletions(-) delete mode 100644 examples/BUILD.bazel delete mode 100644 examples/WORKSPACE.bazel delete mode 100644 examples/foo.proto delete mode 100644 examples/go/foo_proto_test.go create mode 100644 examples/go/greeter_proto_test.go create mode 100644 examples/proto/BUILD.bazel create mode 100644 examples/proto/greeter.proto create mode 100644 examples/proto/src/lib.rs create mode 100644 examples/rust/client/BUILD.bazel create mode 100644 examples/rust/client/src/main.rs create mode 100644 examples/rust/server/BUILD.bazel create mode 100644 examples/rust/server/src/main.rs create mode 100644 examples/rust/server/src/server.rs create mode 100644 examples/rust/server/src/shutdown_utils.rs diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel deleted file mode 100644 index 5eda38d..0000000 --- a/examples/BUILD.bazel +++ /dev/null @@ -1,30 +0,0 @@ -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") - -package(default_visibility = ["//visibility:public"]) - -proto_library( - name = "foo_proto", - srcs = ["foo.proto"], - deps = ["@com_google_protobuf//:any_proto"], -) - -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"], -# ) - -go_proto_library( - name = "foo_go_proto", - importpath = "example.com/foo_proto", - proto = ":foo_proto", -) diff --git a/examples/MODULE.bazel b/examples/MODULE.bazel index a7180ec..b1006ad 100644 --- a/examples/MODULE.bazel +++ b/examples/MODULE.bazel @@ -6,6 +6,8 @@ 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 +74,70 @@ 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") 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/proto/BUILD.bazel b/examples/proto/BUILD.bazel new file mode 100644 index 0000000..62cb8a1 --- /dev/null +++ b/examples/proto/BUILD.bazel @@ -0,0 +1,39 @@ +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"], +) 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/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..0bcb005 --- /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: "Hello gRPC".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/toolchains/BUILD.bazel b/examples/tools/toolchains/BUILD.bazel index 1286682..6c335f6 100644 --- a/examples/tools/toolchains/BUILD.bazel +++ b/examples/tools/toolchains/BUILD.bazel @@ -6,6 +6,8 @@ See https://bazel.build/tutorials/ccp-toolchain-config """ load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain") +load("@rules_rust//rust:defs.bzl", "rust_library_group") +load("@rules_rust_prost//:defs.bzl", "rust_prost_toolchain") load("defs.bzl", "cc_toolchain_config") # Configure protoc to have the right arguments for generating Python stubs. @@ -27,6 +29,36 @@ proto_lang_toolchain( toolchain_type = "@rules_java//java/proto:toolchain_type", ) +rust_library_group( + name = "prost_runtime", + deps = [ + "@crates//:prost", + ], +) + +rust_library_group( + name = "tonic_runtime", + deps = [ + ":prost_runtime", + "@crates//:tonic", + ], +) + +rust_prost_toolchain( + name = "prost_toolchain_impl", + prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost", + prost_runtime = ":prost_runtime", + prost_types = "@crates//:prost-types", + tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic", + tonic_runtime = ":tonic_runtime", +) + +toolchain( + name = "prost_toolchain", + toolchain = "prost_toolchain_impl", + toolchain_type = "@rules_rust_prost//: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. @@ -48,8 +80,8 @@ cc_toolchain( toolchain_identifier = "noop-toolchain", ) -toolchain( - name = "cc_toolchain", - toolchain = ":noop_toolchain", - toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", -) +# toolchain( +# name = "cc_toolchain", +# toolchain = ":noop_toolchain", +# toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +# ) From 6f0c871bcfb8b2bdb78d519358e50118844ae0b2 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Mon, 17 Mar 2025 23:21:03 -0700 Subject: [PATCH 2/6] feat: demonstrate TypeScript node client --- .gitignore | 1 + examples/.bazelignore | 1 + examples/.bazelrc | 2 + examples/BUILD.bazel | 19 +++ examples/MODULE.bazel | 29 +++++ examples/localhost+2-key.pem | 28 +++++ examples/localhost+2.pem | 26 ++++ examples/package.json | 13 ++ examples/pnpm-lock.yaml | 160 +++++++++++++++++++++++++ examples/proto/BUILD.bazel | 9 ++ examples/proto/greeter_pb.d.ts | 67 +++++++++++ examples/rust/client/src/main.rs | 2 +- examples/tsconfig.json | 7 ++ examples/typescript/client/BUILD.bazel | 24 ++++ examples/typescript/client/main.mts | 16 +++ 15 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 examples/.bazelignore create mode 100644 examples/BUILD.bazel create mode 100644 examples/localhost+2-key.pem create mode 100644 examples/localhost+2.pem create mode 100644 examples/package.json create mode 100644 examples/pnpm-lock.yaml create mode 100644 examples/proto/greeter_pb.d.ts create mode 100644 examples/tsconfig.json create mode 100644 examples/typescript/client/BUILD.bazel create mode 100644 examples/typescript/client/main.mts 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/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 new file mode 100644 index 0000000..20bd431 --- /dev/null +++ b/examples/BUILD.bazel @@ -0,0 +1,19 @@ +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"]) + +copy_to_bin( + name = "package_json", + srcs = ["package.json"], +) + +# Link all direct dependencies in /package.json to +# bazel-bin/node_modules +npm_link_all_packages(name = "node_modules") + +ts_config( + name = "tsconfig", + src = "tsconfig.json", +) diff --git a/examples/MODULE.bazel b/examples/MODULE.bazel index b1006ad..c70cebd 100644 --- a/examples/MODULE.bazel +++ b/examples/MODULE.bazel @@ -1,6 +1,8 @@ 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") @@ -141,3 +143,30 @@ crate.spec( ) 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/localhost+2-key.pem b/examples/localhost+2-key.pem new file mode 100644 index 0000000..ee36bc4 --- /dev/null +++ b/examples/localhost+2-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC04ZLZNMOIvhss +9AmAIAYcQL++XytjkBrIJ8wwEg0hAUhRiMJwKo8tDuHvOlFUKzMlgVC8/tGe3Uwh +bUb7/xgO5q3HmadzslMLbtt09MI9n9GrltxLAjKnef7I+BtkUhprXafGkHCcqtLU +LImKTAVx+GlD7oo+bhIoI68+u4oR0zaLf4zfSuUn+VE4PuclaGSThllLZ0ryIGcJ +RGvW0OFTweJKWxVCTgmXx4RSZeNpMoOuTcaYg/VxCCBwHuSjqlXcDmzVWR2DPoc3 +pnc3N2Iymf/eSGv2Gt7ZwW/ymN8CQ2LwTME5V3FlSsRhcdw7rLEfBm2GoTUp4ebT +/gb+g1oxAgMBAAECggEBAI946TDuYDaDjCyw+SQuwooAdda7yD+12vhuUNDEULOg +P8ukbY3oxB5aUq2dlUrs5SnXk8IFYSHgqHVPJ2HUqjGPmcHbx+3GQYatDNeNGNEm +hnnTNLMucB1Vb9naqmd9lEUbSWv/v8MU4Bu5o/MVb7BB+MUQXYk9Z5t9CpD40oBl +sckxi8UOJnvcc9S54Yu4uMFklHSyj3TMJU637k3O4auM2RgCbFjz39GWjNRiCkd5 +cPfDrohGErk/hu+7rNDRvjkn3CuHKDyM+YKBUiuog2mFE6pPy4eIweU8w8DWVFfC +GV9PsqjsPDln9kzqz1mecMo5iZy+ZvoO1Tg8t7XtO90CgYEA0skaH894DDbQM/rl +XQW86zMJo8rlVcsbWeWn5L75xpxYEgz4C/D51+YI3JKBleYMtTqSSNviYqbi83hG +C7mmY+AA4L1SGzekMV1+P6/Y98F1+x8s5gugSlVx8dhFFWG+vk0p3Py1c3Cn0RKx +nQMdKso3iamdY1Y2tUYbTjrIBJ8CgYEA265Tkv+mvoQfmKgGWvZBvmGMmgkfkQll +EABCx7TQUNdw4dJWHf/g3nH0FgiJWHFMDKUapkChJRw/lLcapzi6lj99vWcgR1iG +MrFF7x8H8V+P5JTbOihpCAfDDiqqwHOvwNB1NTSbJqFfuZdENSIQ0gP5BYbw8JRI +tVQjmY283y8CgYAtMSajuVSQsdPTwTAZ0JgfiTLA5khjK4eyr3Veqr9coLqVLCim +TsUST+SIffTAkbEZzfP9IP+ZjRRNhPTnoKcW9Ljbdlu7MCPI3bWqq+YFwHmuHJIA +xG9aYJVsd6TgH7PIkzytf5TbqkSgo7Rm6HsBaJedsTroSFy0YtKJ5DpsGwKBgQCb +eR7w1DoAb6Wk9pW43rvcr1FA2uAaV5nM30Jj8FXWQQNE7wW/qY5OIDvtNBFwJI78 +DAV2UBs8FmfxKj2Ux5NWLo0g9NFlbQNc8RVbjIykiUtfLPKSkHL1Gfk0F4JNPhLO +1Tl+dEKx7le/E41URU2+NM2S2dO/kFJ88pVXYXagRQKBgQCWmbaf8muwldgIJ0BU ++OBApkyC8MH3Zir/Y4ynpOs7oENM8urpO0PSs079IL8senrGour8YTesy85qxKTW +Gfv8Vc/LOKWyFzXFTxa9zAIBowmoP1zqIpaUQxrYVckX+vZ4O8IQkVT7fslD1Im5 +bRSqtwV+DxNr0SI2Y8OWg32P3Q== +-----END PRIVATE KEY----- diff --git a/examples/localhost+2.pem b/examples/localhost+2.pem new file mode 100644 index 0000000..ac659f4 --- /dev/null +++ b/examples/localhost+2.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEbjCCAtagAwIBAgIRAPoGqA2zKkvJJU1IajOdtrowDQYJKoZIhvcNAQELBQAw +gY8xHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEyMDAGA1UECwwpYWxl +eGVhZ2xlQGFzcGVjdC1idWlsZC5sb2NhbCAoQWxleCBFYWdsZSkxOTA3BgNVBAMM +MG1rY2VydCBhbGV4ZWFnbGVAYXNwZWN0LWJ1aWxkLmxvY2FsIChBbGV4IEVhZ2xl +KTAeFw0yNTAzMTgwNjE3NDZaFw0yNzA2MTgwNjE3NDZaMF0xJzAlBgNVBAoTHm1r +Y2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTEyMDAGA1UECwwpYWxleGVhZ2xl +QGFzcGVjdC1idWlsZC5sb2NhbCAoQWxleCBFYWdsZSkwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC04ZLZNMOIvhss9AmAIAYcQL++XytjkBrIJ8wwEg0h +AUhRiMJwKo8tDuHvOlFUKzMlgVC8/tGe3UwhbUb7/xgO5q3HmadzslMLbtt09MI9 +n9GrltxLAjKnef7I+BtkUhprXafGkHCcqtLULImKTAVx+GlD7oo+bhIoI68+u4oR +0zaLf4zfSuUn+VE4PuclaGSThllLZ0ryIGcJRGvW0OFTweJKWxVCTgmXx4RSZeNp +MoOuTcaYg/VxCCBwHuSjqlXcDmzVWR2DPoc3pnc3N2Iymf/eSGv2Gt7ZwW/ymN8C +Q2LwTME5V3FlSsRhcdw7rLEfBm2GoTUp4ebT/gb+g1oxAgMBAAGjdjB0MA4GA1Ud +DwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBQv6gmv +UFR+bA8FOi4MoBE3xtM9qTAsBgNVHREEJTAjgglsb2NhbGhvc3SHBH8AAAGHEAAA +AAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggGBAIiLii7TDzQ2g+uQ30fL +ehDyooWo5fl1BKESmeeb9kimQqYgDtgFideMiuYMFKe3umUbj3pGCDDTWJCqtsMU +26zrEqUP6VGEx/YSsira2zFIjY5P/Np58sZT+P7Pcrv7vBDJoUDUPCeCfM3NANfw +x6eYpvi3lYDY9b6CgM4lOqlLFl3b7lIZbD4GK/z+ISzMJCyQw6fuJJn6muMzNtKd +uYHienDAn5PbXdALqlV74U5g2dJy3YOE8NNmYN7pURSkEimSrYm/AQ4IGDP+8b4g +EuNnN9muh5FOEoem6XwO3LD/OmJ0BhE03lkVYZa8bLiBE1xR0B70L+RFKv4DfIln +dGo7urW1nh8je6No0WLcJA7nUYe8NmzuzJGA6Id6y9vbIFv7e5jBMu51IpQt5l4h +3983u7HEa2Th054KjhaEj922qcO6URUesajOsiEPQlaA1hgVMdS/vDN0G7dSryJT +ENy5wq9yXSq39716XvgjUkpcD41rb+z3+AGP6giqnco/eQ== +-----END CERTIFICATE----- diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000..ba45357 --- /dev/null +++ b/examples/package.json @@ -0,0 +1,13 @@ +{ + "dependencies": { + "@bufbuild/protobuf": "^2.2.4", + "@connectrpc/connect-node": "2.0.2" + }, + "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..66844c1 --- /dev/null +++ b/examples/pnpm-lock.yaml @@ -0,0 +1,160 @@ +lockfileVersion: "6.0" + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + "@bufbuild/protobuf": + specifier: ^2.2.4 + version: 2.2.4 + "@connectrpc/connect-node": + specifier: 2.0.2 + version: 2.0.2(@bufbuild/protobuf@2.2.4)(@connectrpc/connect@2.0.2) + +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-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 + + /@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 + + /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 + + /ms@2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + dev: true + + /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 index 62cb8a1..88c206c 100644 --- a/examples/proto/BUILD.bazel +++ b/examples/proto/BUILD.bazel @@ -1,3 +1,4 @@ +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") @@ -37,3 +38,11 @@ rust_prost_library( 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_pb.d.ts b/examples/proto/greeter_pb.d.ts new file mode 100644 index 0000000..084ea1a --- /dev/null +++ b/examples/proto/greeter_pb.d.ts @@ -0,0 +1,67 @@ +// @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/rust/client/src/main.rs b/examples/rust/client/src/main.rs index 0bcb005..f4949aa 100644 --- a/examples/rust/client/src/main.rs +++ b/examples/rust/client/src/main.rs @@ -14,7 +14,7 @@ async fn main() -> Result<(), Box> { value: b"details".to_vec(), }; let request = tonic::Request::new(HelloRequest { - name: "Hello gRPC".into(), + name: "Rust Client".into(), details: vec![detail], }); diff --git a/examples/tsconfig.json b/examples/tsconfig.json new file mode 100644 index 0000000..054c055 --- /dev/null +++ b/examples/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "lib": ["ES2018"], + "module": "Node16", + "moduleResolution": "node16" + } +} diff --git a/examples/typescript/client/BUILD.bazel b/examples/typescript/client/BUILD.bazel new file mode 100644 index 0000000..8204fcf --- /dev/null +++ b/examples/typescript/client/BUILD.bazel @@ -0,0 +1,24 @@ +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 = [ + "//:package_json", + "//proto:greeter_ts_proto", + ], + entry_point = "main.mjs", +) diff --git a/examples/typescript/client/main.mts b/examples/typescript/client/main.mts new file mode 100644 index 0000000..0c4658e --- /dev/null +++ b/examples/typescript/client/main.mts @@ -0,0 +1,16 @@ +import { createClient } 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", + }); + console.log((res as /*todo*/any).message); +} +void main(); From 52e697748003c5ad45d13e7f73ca7fb5a139ceb9 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Mon, 17 Mar 2025 23:49:32 -0700 Subject: [PATCH 3/6] feat: add typescript server --- .prettierignore | 1 + examples/localhost+2-key.pem | 28 -- examples/localhost+2.pem | 26 -- examples/package.json | 4 +- examples/pnpm-lock.yaml | 446 +++++++++++++++++++++++++ examples/proto/greeter_pb.d.ts | 9 +- examples/tsconfig.json | 5 +- examples/typescript/client/BUILD.bazel | 5 +- examples/typescript/client/main.mts | 9 +- examples/typescript/server/BUILD.bazel | 25 ++ examples/typescript/server/connect.mts | 11 + examples/typescript/server/main.mts | 19 ++ 12 files changed, 519 insertions(+), 69 deletions(-) delete mode 100644 examples/localhost+2-key.pem delete mode 100644 examples/localhost+2.pem create mode 100644 examples/typescript/server/BUILD.bazel create mode 100644 examples/typescript/server/connect.mts create mode 100644 examples/typescript/server/main.mts 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/localhost+2-key.pem b/examples/localhost+2-key.pem deleted file mode 100644 index ee36bc4..0000000 --- a/examples/localhost+2-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC04ZLZNMOIvhss -9AmAIAYcQL++XytjkBrIJ8wwEg0hAUhRiMJwKo8tDuHvOlFUKzMlgVC8/tGe3Uwh -bUb7/xgO5q3HmadzslMLbtt09MI9n9GrltxLAjKnef7I+BtkUhprXafGkHCcqtLU -LImKTAVx+GlD7oo+bhIoI68+u4oR0zaLf4zfSuUn+VE4PuclaGSThllLZ0ryIGcJ -RGvW0OFTweJKWxVCTgmXx4RSZeNpMoOuTcaYg/VxCCBwHuSjqlXcDmzVWR2DPoc3 -pnc3N2Iymf/eSGv2Gt7ZwW/ymN8CQ2LwTME5V3FlSsRhcdw7rLEfBm2GoTUp4ebT -/gb+g1oxAgMBAAECggEBAI946TDuYDaDjCyw+SQuwooAdda7yD+12vhuUNDEULOg -P8ukbY3oxB5aUq2dlUrs5SnXk8IFYSHgqHVPJ2HUqjGPmcHbx+3GQYatDNeNGNEm -hnnTNLMucB1Vb9naqmd9lEUbSWv/v8MU4Bu5o/MVb7BB+MUQXYk9Z5t9CpD40oBl -sckxi8UOJnvcc9S54Yu4uMFklHSyj3TMJU637k3O4auM2RgCbFjz39GWjNRiCkd5 -cPfDrohGErk/hu+7rNDRvjkn3CuHKDyM+YKBUiuog2mFE6pPy4eIweU8w8DWVFfC -GV9PsqjsPDln9kzqz1mecMo5iZy+ZvoO1Tg8t7XtO90CgYEA0skaH894DDbQM/rl -XQW86zMJo8rlVcsbWeWn5L75xpxYEgz4C/D51+YI3JKBleYMtTqSSNviYqbi83hG -C7mmY+AA4L1SGzekMV1+P6/Y98F1+x8s5gugSlVx8dhFFWG+vk0p3Py1c3Cn0RKx -nQMdKso3iamdY1Y2tUYbTjrIBJ8CgYEA265Tkv+mvoQfmKgGWvZBvmGMmgkfkQll -EABCx7TQUNdw4dJWHf/g3nH0FgiJWHFMDKUapkChJRw/lLcapzi6lj99vWcgR1iG -MrFF7x8H8V+P5JTbOihpCAfDDiqqwHOvwNB1NTSbJqFfuZdENSIQ0gP5BYbw8JRI -tVQjmY283y8CgYAtMSajuVSQsdPTwTAZ0JgfiTLA5khjK4eyr3Veqr9coLqVLCim -TsUST+SIffTAkbEZzfP9IP+ZjRRNhPTnoKcW9Ljbdlu7MCPI3bWqq+YFwHmuHJIA -xG9aYJVsd6TgH7PIkzytf5TbqkSgo7Rm6HsBaJedsTroSFy0YtKJ5DpsGwKBgQCb -eR7w1DoAb6Wk9pW43rvcr1FA2uAaV5nM30Jj8FXWQQNE7wW/qY5OIDvtNBFwJI78 -DAV2UBs8FmfxKj2Ux5NWLo0g9NFlbQNc8RVbjIykiUtfLPKSkHL1Gfk0F4JNPhLO -1Tl+dEKx7le/E41URU2+NM2S2dO/kFJ88pVXYXagRQKBgQCWmbaf8muwldgIJ0BU -+OBApkyC8MH3Zir/Y4ynpOs7oENM8urpO0PSs079IL8senrGour8YTesy85qxKTW -Gfv8Vc/LOKWyFzXFTxa9zAIBowmoP1zqIpaUQxrYVckX+vZ4O8IQkVT7fslD1Im5 -bRSqtwV+DxNr0SI2Y8OWg32P3Q== ------END PRIVATE KEY----- diff --git a/examples/localhost+2.pem b/examples/localhost+2.pem deleted file mode 100644 index ac659f4..0000000 --- a/examples/localhost+2.pem +++ /dev/null @@ -1,26 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEbjCCAtagAwIBAgIRAPoGqA2zKkvJJU1IajOdtrowDQYJKoZIhvcNAQELBQAw -gY8xHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEyMDAGA1UECwwpYWxl -eGVhZ2xlQGFzcGVjdC1idWlsZC5sb2NhbCAoQWxleCBFYWdsZSkxOTA3BgNVBAMM -MG1rY2VydCBhbGV4ZWFnbGVAYXNwZWN0LWJ1aWxkLmxvY2FsIChBbGV4IEVhZ2xl -KTAeFw0yNTAzMTgwNjE3NDZaFw0yNzA2MTgwNjE3NDZaMF0xJzAlBgNVBAoTHm1r -Y2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTEyMDAGA1UECwwpYWxleGVhZ2xl -QGFzcGVjdC1idWlsZC5sb2NhbCAoQWxleCBFYWdsZSkwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQC04ZLZNMOIvhss9AmAIAYcQL++XytjkBrIJ8wwEg0h -AUhRiMJwKo8tDuHvOlFUKzMlgVC8/tGe3UwhbUb7/xgO5q3HmadzslMLbtt09MI9 -n9GrltxLAjKnef7I+BtkUhprXafGkHCcqtLULImKTAVx+GlD7oo+bhIoI68+u4oR -0zaLf4zfSuUn+VE4PuclaGSThllLZ0ryIGcJRGvW0OFTweJKWxVCTgmXx4RSZeNp -MoOuTcaYg/VxCCBwHuSjqlXcDmzVWR2DPoc3pnc3N2Iymf/eSGv2Gt7ZwW/ymN8C -Q2LwTME5V3FlSsRhcdw7rLEfBm2GoTUp4ebT/gb+g1oxAgMBAAGjdjB0MA4GA1Ud -DwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBQv6gmv -UFR+bA8FOi4MoBE3xtM9qTAsBgNVHREEJTAjgglsb2NhbGhvc3SHBH8AAAGHEAAA -AAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggGBAIiLii7TDzQ2g+uQ30fL -ehDyooWo5fl1BKESmeeb9kimQqYgDtgFideMiuYMFKe3umUbj3pGCDDTWJCqtsMU -26zrEqUP6VGEx/YSsira2zFIjY5P/Np58sZT+P7Pcrv7vBDJoUDUPCeCfM3NANfw -x6eYpvi3lYDY9b6CgM4lOqlLFl3b7lIZbD4GK/z+ISzMJCyQw6fuJJn6muMzNtKd -uYHienDAn5PbXdALqlV74U5g2dJy3YOE8NNmYN7pURSkEimSrYm/AQ4IGDP+8b4g -EuNnN9muh5FOEoem6XwO3LD/OmJ0BhE03lkVYZa8bLiBE1xR0B70L+RFKv4DfIln -dGo7urW1nh8je6No0WLcJA7nUYe8NmzuzJGA6Id6y9vbIFv7e5jBMu51IpQt5l4h -3983u7HEa2Th054KjhaEj922qcO6URUesajOsiEPQlaA1hgVMdS/vDN0G7dSryJT -ENy5wq9yXSq39716XvgjUkpcD41rb+z3+AGP6giqnco/eQ== ------END CERTIFICATE----- diff --git a/examples/package.json b/examples/package.json index ba45357..3597763 100644 --- a/examples/package.json +++ b/examples/package.json @@ -1,7 +1,9 @@ { "dependencies": { "@bufbuild/protobuf": "^2.2.4", - "@connectrpc/connect-node": "2.0.2" + "@connectrpc/connect-node": "2.0.2", + "@connectrpc/connect-fastify": "~2.0.2", + "fastify": "~5.2.1" }, "devDependencies": { "@bufbuild/protoc-gen-es": "~2.2.4", diff --git a/examples/pnpm-lock.yaml b/examples/pnpm-lock.yaml index 66844c1..f2b58ab 100644 --- a/examples/pnpm-lock.yaml +++ b/examples/pnpm-lock.yaml @@ -8,9 +8,15 @@ 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": @@ -65,6 +71,24 @@ packages: - 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: { @@ -89,6 +113,59 @@ packages: 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: { @@ -112,6 +189,65 @@ packages: - 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: { @@ -127,6 +263,145 @@ packages: 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: { @@ -134,6 +409,177 @@ packages: } 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: { diff --git a/examples/proto/greeter_pb.d.ts b/examples/proto/greeter_pb.d.ts index 084ea1a..67922cd 100644 --- a/examples/proto/greeter_pb.d.ts +++ b/examples/proto/greeter_pb.d.ts @@ -2,11 +2,7 @@ // @generated from file proto/greeter.proto (package proto, syntax proto3) /* eslint-disable */ -import type { - GenFile, - GenMessage, - GenService, -} from "@bufbuild/protobuf/codegenv1"; +import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1"; import type { Message } from "@bufbuild/protobuf"; import type { Any } from "@bufbuild/protobuf/wkt"; @@ -63,5 +59,6 @@ export declare const Greeter: GenService<{ methodKind: "unary"; input: typeof HelloRequestSchema; output: typeof HelloReplySchema; - }; + }, }>; + diff --git a/examples/tsconfig.json b/examples/tsconfig.json index 054c055..d5cb4df 100644 --- a/examples/tsconfig.json +++ b/examples/tsconfig.json @@ -1,7 +1,8 @@ { "compilerOptions": { "lib": ["ES2018"], - "module": "Node16", - "moduleResolution": "node16" + "module": "ES2022", + "target": "ES2017", + "moduleResolution": "node" } } diff --git a/examples/typescript/client/BUILD.bazel b/examples/typescript/client/BUILD.bazel index 8204fcf..464ce97 100644 --- a/examples/typescript/client/BUILD.bazel +++ b/examples/typescript/client/BUILD.bazel @@ -16,9 +16,6 @@ ts_project( js_binary( name = "client", - data = [ - "//:package_json", - "//proto:greeter_ts_proto", - ], + data = [":main"], entry_point = "main.mjs", ) diff --git a/examples/typescript/client/main.mts b/examples/typescript/client/main.mts index 0c4658e..4c8613c 100644 --- a/examples/typescript/client/main.mts +++ b/examples/typescript/client/main.mts @@ -1,4 +1,4 @@ -import { createClient } from "@connectrpc/connect"; +import { createClient , CallOptions} from "@connectrpc/connect"; import { createGrpcTransport } from "@connectrpc/connect-node"; import {Greeter} from "../../proto/greeter_pb.js"; @@ -10,7 +10,12 @@ 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(); From 059534787d8aae07f2b3298dd4dbed57153ce7fa Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Tue, 18 Mar 2025 11:43:24 -0700 Subject: [PATCH 4/6] refactor: remove non-functional cc toolchain Rust depends on having one that works. We can find a more surgical way to prevent protoc cc_binary from getting built. --- examples/tools/toolchains/BUILD.bazel | 55 +-------------------------- examples/tools/toolchains/defs.bzl | 20 ---------- 2 files changed, 2 insertions(+), 73 deletions(-) delete mode 100644 examples/tools/toolchains/defs.bzl diff --git a/examples/tools/toolchains/BUILD.bazel b/examples/tools/toolchains/BUILD.bazel index 6c335f6..e3e5bb0 100644 --- a/examples/tools/toolchains/BUILD.bazel +++ b/examples/tools/toolchains/BUILD.bazel @@ -1,14 +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("@rules_rust//rust:defs.bzl", "rust_library_group") load("@rules_rust_prost//:defs.bzl", "rust_prost_toolchain") -load("defs.bzl", "cc_toolchain_config") # 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. @@ -29,28 +20,13 @@ proto_lang_toolchain( toolchain_type = "@rules_java//java/proto:toolchain_type", ) -rust_library_group( - name = "prost_runtime", - deps = [ - "@crates//:prost", - ], -) - -rust_library_group( - name = "tonic_runtime", - deps = [ - ":prost_runtime", - "@crates//:tonic", - ], -) - rust_prost_toolchain( name = "prost_toolchain_impl", prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost", - prost_runtime = ":prost_runtime", + prost_runtime = "//rust:prost_runtime", prost_types = "@crates//:prost-types", tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic", - tonic_runtime = ":tonic_runtime", + tonic_runtime = "//rust:tonic_runtime", ) toolchain( @@ -58,30 +34,3 @@ toolchain( toolchain = "prost_toolchain_impl", toolchain_type = "@rules_rust_prost//: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", -) - -# toolchain( -# name = "cc_toolchain", -# toolchain = ":noop_toolchain", -# toolchain_type = "@bazel_tools//tools/cpp: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], -) From 9ee3b550bf42a9beab2a9226dd9fd6230fd4e705 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Tue, 18 Mar 2025 11:45:29 -0700 Subject: [PATCH 5/6] chore: missing file --- examples/rust/BUILD.bazel | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 examples/rust/BUILD.bazel diff --git a/examples/rust/BUILD.bazel b/examples/rust/BUILD.bazel new file mode 100644 index 0000000..e1bb6b2 --- /dev/null +++ b/examples/rust/BUILD.bazel @@ -0,0 +1,18 @@ +load("@rules_rust//rust:defs.bzl", "rust_library_group") + +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", + ], +) From 7ba931fa8cba2dcd14aca16eae923229d98890d4 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Tue, 18 Mar 2025 11:50:01 -0700 Subject: [PATCH 6/6] refactor: move to tools --- examples/rust/BUILD.bazel | 18 ------------------ examples/tools/BUILD.bazel | 18 ++++++++++++++++++ examples/tools/toolchains/BUILD.bazel | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 examples/rust/BUILD.bazel diff --git a/examples/rust/BUILD.bazel b/examples/rust/BUILD.bazel deleted file mode 100644 index e1bb6b2..0000000 --- a/examples/rust/BUILD.bazel +++ /dev/null @@ -1,18 +0,0 @@ -load("@rules_rust//rust:defs.bzl", "rust_library_group") - -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", - ], -) 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 e3e5bb0..ccb0c72 100644 --- a/examples/tools/toolchains/BUILD.bazel +++ b/examples/tools/toolchains/BUILD.bazel @@ -23,10 +23,10 @@ proto_lang_toolchain( rust_prost_toolchain( name = "prost_toolchain_impl", prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost", - prost_runtime = "//rust:prost_runtime", + prost_runtime = "//tools:prost_runtime", prost_types = "@crates//:prost-types", tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic", - tonic_runtime = "//rust:tonic_runtime", + tonic_runtime = "//tools:tonic_runtime", ) toolchain(