WIP - Cross test impl

This commit is contained in:
Alec Thilenius 2023-05-27 15:08:34 -07:00
parent ccbebb8dce
commit 8365d4f8ba
16 changed files with 1750 additions and 0 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/target
/Cargo.lock
node_modules/

View file

@ -0,0 +1,15 @@
[package]
name = "axum-connect-crosstest"
version = "0.1.0"
edition = "2021"
[dependencies]
async-stream = "0.3.5"
axum = "0.6.9"
axum-connect = { path = "../axum-connect" }
prost = "0.11.9"
tokio = { version = "1.0", features = ["full"] }
tower-http = { version = "0.4.0", features = ["cors"] }
[build-dependencies]
axum-connect-build = { path = "../axum-connect-build" }

View file

@ -0,0 +1,7 @@
use axum_connect_build::{axum_connect_codegen, AxumConnectGenSettings};
fn main() {
let settings = AxumConnectGenSettings::from_directory_recursive("proto")
.expect("failed to glob proto files");
axum_connect_codegen(settings).unwrap();
}

View file

@ -0,0 +1 @@
@buf:registry=https://buf.build/gen/npm/v1/

View file

@ -0,0 +1,8 @@
version: v1
plugins:
- plugin: es
out: gen
opt: target=ts
- plugin: connect-es
out: gen
opt: target=ts

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>axum-connect-crosstest</title>
<style>
* {
font-family: monospace;
}
</style>
</head>
<body>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View file

@ -0,0 +1,989 @@
{
"name": "frontend",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "frontend",
"version": "0.0.1",
"license": "MIT",
"dependencies": {
"@buf/grpc_grpc.bufbuild_connect-es": "^0.9.0-20230516211939-d8bc6b0fb32a.1",
"@bufbuild/connect": "^0.9.0",
"@bufbuild/connect-web": "^0.9.0",
"vite": "^4.3.9"
},
"devDependencies": {
"@bufbuild/buf": "^1.19.0-1",
"@bufbuild/protoc-gen-connect-es": "^0.9.0",
"@bufbuild/protoc-gen-es": "^1.2.0",
"typescript": "^5.0.4"
}
},
"node_modules/@buf/cncf_xds.bufbuild_connect-es": {
"version": "0.9.0-20230428204815-197fca8a74c5.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/cncf_xds.bufbuild_connect-es/-/cncf_xds.bufbuild_connect-es-0.9.0-20230428204815-197fca8a74c5.1.tgz",
"dependencies": {
"@buf/cncf_xds.bufbuild_es": "1.2.0-20230428204815-197fca8a74c5.1",
"@buf/envoyproxy_protoc-gen-validate.bufbuild_connect-es": "0.9.0-20221025150516-6607b10f00ed.1",
"@buf/googleapis_googleapis.bufbuild_connect-es": "0.9.0-20230329151039-5ae7f88519b0.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/cncf_xds.bufbuild_connect-es/node_modules/@buf/googleapis_googleapis.bufbuild_connect-es": {
"version": "0.9.0-20230329151039-5ae7f88519b0.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_connect-es/-/googleapis_googleapis.bufbuild_connect-es-0.9.0-20230329151039-5ae7f88519b0.1.tgz",
"dependencies": {
"@buf/googleapis_googleapis.bufbuild_es": "1.2.0-20230329151039-5ae7f88519b0.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/cncf_xds.bufbuild_es": {
"version": "1.2.0-20230428204815-197fca8a74c5.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/cncf_xds.bufbuild_es/-/cncf_xds.bufbuild_es-1.2.0-20230428204815-197fca8a74c5.1.tgz",
"dependencies": {
"@buf/envoyproxy_protoc-gen-validate.bufbuild_es": "1.2.0-20221025150516-6607b10f00ed.1",
"@buf/googleapis_googleapis.bufbuild_es": "1.2.0-20230329151039-5ae7f88519b0.1"
},
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/envoyproxy_envoy.bufbuild_connect-es": {
"version": "0.9.0-20230516211932-3afde44c0a3a.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/envoyproxy_envoy.bufbuild_connect-es/-/envoyproxy_envoy.bufbuild_connect-es-0.9.0-20230516211932-3afde44c0a3a.1.tgz",
"dependencies": {
"@buf/cncf_xds.bufbuild_connect-es": "0.9.0-20230428204815-197fca8a74c5.1",
"@buf/envoyproxy_envoy.bufbuild_es": "1.2.0-20230516211932-3afde44c0a3a.1",
"@buf/envoyproxy_protoc-gen-validate.bufbuild_connect-es": "0.9.0-20221025150516-6607b10f00ed.1",
"@buf/googleapis_googleapis.bufbuild_connect-es": "0.9.0-20230502210827-cc916c318597.1",
"@buf/opencensus_opencensus.bufbuild_connect-es": "0.9.0-20230503204408-7e4755513505.1",
"@buf/opentelemetry_opentelemetry.bufbuild_connect-es": "0.9.0-20230516211923-547fa0c6b925.1",
"@buf/prometheus_client-model.bufbuild_connect-es": "0.9.0-20230331140308-55bcfe88c9e5.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/envoyproxy_envoy.bufbuild_es": {
"version": "1.2.0-20230516211932-3afde44c0a3a.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/envoyproxy_envoy.bufbuild_es/-/envoyproxy_envoy.bufbuild_es-1.2.0-20230516211932-3afde44c0a3a.1.tgz",
"dependencies": {
"@buf/cncf_xds.bufbuild_es": "1.2.0-20230428204815-197fca8a74c5.1",
"@buf/envoyproxy_protoc-gen-validate.bufbuild_es": "1.2.0-20221025150516-6607b10f00ed.1",
"@buf/googleapis_googleapis.bufbuild_es": "1.2.0-20230502210827-cc916c318597.1",
"@buf/opencensus_opencensus.bufbuild_es": "1.2.0-20230503204408-7e4755513505.1",
"@buf/opentelemetry_opentelemetry.bufbuild_es": "1.2.0-20230516211923-547fa0c6b925.1",
"@buf/prometheus_client-model.bufbuild_es": "1.2.0-20230331140308-55bcfe88c9e5.1"
},
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/envoyproxy_envoy.bufbuild_es/node_modules/@buf/googleapis_googleapis.bufbuild_es": {
"version": "1.2.0-20230502210827-cc916c318597.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.2.0-20230502210827-cc916c318597.1.tgz",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/envoyproxy_protoc-gen-validate.bufbuild_connect-es": {
"version": "0.9.0-20221025150516-6607b10f00ed.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/envoyproxy_protoc-gen-validate.bufbuild_connect-es/-/envoyproxy_protoc-gen-validate.bufbuild_connect-es-0.9.0-20221025150516-6607b10f00ed.1.tgz",
"dependencies": {
"@buf/envoyproxy_protoc-gen-validate.bufbuild_es": "1.2.0-20221025150516-6607b10f00ed.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/envoyproxy_protoc-gen-validate.bufbuild_es": {
"version": "1.2.0-20221025150516-6607b10f00ed.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/envoyproxy_protoc-gen-validate.bufbuild_es/-/envoyproxy_protoc-gen-validate.bufbuild_es-1.2.0-20221025150516-6607b10f00ed.1.tgz",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/googleapis_googleapis.bufbuild_connect-es": {
"version": "0.9.0-20230502210827-cc916c318597.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_connect-es/-/googleapis_googleapis.bufbuild_connect-es-0.9.0-20230502210827-cc916c318597.1.tgz",
"dependencies": {
"@buf/googleapis_googleapis.bufbuild_es": "1.2.0-20230502210827-cc916c318597.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/googleapis_googleapis.bufbuild_connect-es/node_modules/@buf/googleapis_googleapis.bufbuild_es": {
"version": "1.2.0-20230502210827-cc916c318597.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.2.0-20230502210827-cc916c318597.1.tgz",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/googleapis_googleapis.bufbuild_es": {
"version": "1.2.0-20230329151039-5ae7f88519b0.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.2.0-20230329151039-5ae7f88519b0.1.tgz",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/grpc_grpc.bufbuild_connect-es": {
"version": "0.9.0-20230516211939-d8bc6b0fb32a.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/grpc_grpc.bufbuild_connect-es/-/grpc_grpc.bufbuild_connect-es-0.9.0-20230516211939-d8bc6b0fb32a.1.tgz",
"dependencies": {
"@buf/cncf_xds.bufbuild_connect-es": "0.9.0-20230428204815-197fca8a74c5.1",
"@buf/envoyproxy_envoy.bufbuild_connect-es": "0.9.0-20230516211932-3afde44c0a3a.1",
"@buf/envoyproxy_protoc-gen-validate.bufbuild_connect-es": "0.9.0-20221025150516-6607b10f00ed.1",
"@buf/googleapis_googleapis.bufbuild_connect-es": "0.9.0-20230502210827-cc916c318597.1",
"@buf/grpc_grpc.bufbuild_es": "1.2.0-20230516211939-d8bc6b0fb32a.1",
"@buf/opencensus_opencensus.bufbuild_connect-es": "0.9.0-20230503204408-7e4755513505.1",
"@buf/opentelemetry_opentelemetry.bufbuild_connect-es": "0.9.0-20230516211923-547fa0c6b925.1",
"@buf/prometheus_client-model.bufbuild_connect-es": "0.9.0-20230331140308-55bcfe88c9e5.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/grpc_grpc.bufbuild_es": {
"version": "1.2.0-20230516211939-d8bc6b0fb32a.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/grpc_grpc.bufbuild_es/-/grpc_grpc.bufbuild_es-1.2.0-20230516211939-d8bc6b0fb32a.1.tgz",
"dependencies": {
"@buf/cncf_xds.bufbuild_es": "1.2.0-20230428204815-197fca8a74c5.1",
"@buf/envoyproxy_envoy.bufbuild_es": "1.2.0-20230516211932-3afde44c0a3a.1",
"@buf/envoyproxy_protoc-gen-validate.bufbuild_es": "1.2.0-20221025150516-6607b10f00ed.1",
"@buf/googleapis_googleapis.bufbuild_es": "1.2.0-20230502210827-cc916c318597.1",
"@buf/opencensus_opencensus.bufbuild_es": "1.2.0-20230503204408-7e4755513505.1",
"@buf/opentelemetry_opentelemetry.bufbuild_es": "1.2.0-20230516211923-547fa0c6b925.1",
"@buf/prometheus_client-model.bufbuild_es": "1.2.0-20230331140308-55bcfe88c9e5.1"
},
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/grpc_grpc.bufbuild_es/node_modules/@buf/googleapis_googleapis.bufbuild_es": {
"version": "1.2.0-20230502210827-cc916c318597.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/googleapis_googleapis.bufbuild_es/-/googleapis_googleapis.bufbuild_es-1.2.0-20230502210827-cc916c318597.1.tgz",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/opencensus_opencensus.bufbuild_connect-es": {
"version": "0.9.0-20230503204408-7e4755513505.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/opencensus_opencensus.bufbuild_connect-es/-/opencensus_opencensus.bufbuild_connect-es-0.9.0-20230503204408-7e4755513505.1.tgz",
"dependencies": {
"@buf/opencensus_opencensus.bufbuild_es": "1.2.0-20230503204408-7e4755513505.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/opencensus_opencensus.bufbuild_es": {
"version": "1.2.0-20230503204408-7e4755513505.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/opencensus_opencensus.bufbuild_es/-/opencensus_opencensus.bufbuild_es-1.2.0-20230503204408-7e4755513505.1.tgz",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/opentelemetry_opentelemetry.bufbuild_connect-es": {
"version": "0.9.0-20230516211923-547fa0c6b925.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/opentelemetry_opentelemetry.bufbuild_connect-es/-/opentelemetry_opentelemetry.bufbuild_connect-es-0.9.0-20230516211923-547fa0c6b925.1.tgz",
"dependencies": {
"@buf/opentelemetry_opentelemetry.bufbuild_es": "1.2.0-20230516211923-547fa0c6b925.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/opentelemetry_opentelemetry.bufbuild_es": {
"version": "1.2.0-20230516211923-547fa0c6b925.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/opentelemetry_opentelemetry.bufbuild_es/-/opentelemetry_opentelemetry.bufbuild_es-1.2.0-20230516211923-547fa0c6b925.1.tgz",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@buf/prometheus_client-model.bufbuild_connect-es": {
"version": "0.9.0-20230331140308-55bcfe88c9e5.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/prometheus_client-model.bufbuild_connect-es/-/prometheus_client-model.bufbuild_connect-es-0.9.0-20230331140308-55bcfe88c9e5.1.tgz",
"dependencies": {
"@buf/prometheus_client-model.bufbuild_es": "1.2.0-20230331140308-55bcfe88c9e5.1"
},
"peerDependencies": {
"@bufbuild/connect": "^0.9.0"
}
},
"node_modules/@buf/prometheus_client-model.bufbuild_es": {
"version": "1.2.0-20230331140308-55bcfe88c9e5.1",
"resolved": "https://buf.build/gen/npm/v1/@buf/prometheus_client-model.bufbuild_es/-/prometheus_client-model.bufbuild_es-1.2.0-20230331140308-55bcfe88c9e5.1.tgz",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@bufbuild/buf": {
"version": "1.19.0-1",
"resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.19.0-1.tgz",
"integrity": "sha512-TIsLTTQUntr/Xq/IMSULv3dlC3/ZsVwQtWgxmJ++IzSuOW79TFQfq59vFeTWrPa6+QXFMz5t6jkMyD4ghzO5nw==",
"dev": true,
"hasInstallScript": true,
"bin": {
"buf": "bin/buf",
"protoc-gen-buf-breaking": "bin/protoc-gen-buf-breaking",
"protoc-gen-buf-lint": "bin/protoc-gen-buf-lint"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@bufbuild/buf-darwin-arm64": "1.19.0-1",
"@bufbuild/buf-darwin-x64": "1.19.0-1",
"@bufbuild/buf-linux-aarch64": "1.19.0-1",
"@bufbuild/buf-linux-x64": "1.19.0-1",
"@bufbuild/buf-win32-arm64": "1.19.0-1",
"@bufbuild/buf-win32-x64": "1.19.0-1"
}
},
"node_modules/@bufbuild/buf-darwin-arm64": {
"version": "1.19.0-1",
"resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.19.0-1.tgz",
"integrity": "sha512-HsWPii21wm3QSyuxrNq9+Yf8iAgpnC4rNCy4x3d6P1fd/LmgE1NPzQW0ghEZvl9dgAQKkL/4S5bKhlm7kbUdmQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@bufbuild/buf-darwin-x64": {
"version": "1.19.0-1",
"resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.19.0-1.tgz",
"integrity": "sha512-2+Ig7ylYpVh4kms/OeJJVY+X0KX4awPA6hYr7L7aZOIcHwZEM8lWtSTO/se5pQc7dc8FXNiC4YUqHC8yfxxX6Q==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@bufbuild/buf-linux-aarch64": {
"version": "1.19.0-1",
"resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.19.0-1.tgz",
"integrity": "sha512-g/Vxg3WiBr3nhsxsRr2Q81xXJD+0ktHIO3ZJggTG2Sbbl3dh8kyg1iKM6MjJiMP7su5RKCylLigzoEJzVTShyA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@bufbuild/buf-linux-x64": {
"version": "1.19.0-1",
"resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.19.0-1.tgz",
"integrity": "sha512-anYuGx8k/2kp8GPX3eHNUf3IY/01Zpnyw0HaLPXK1Btqyy6XkapVywrDqg7YUzMd1ySFEp1wD9UqRNdEFNCQ4A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@bufbuild/buf-win32-arm64": {
"version": "1.19.0-1",
"resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.19.0-1.tgz",
"integrity": "sha512-xXgF1qYnCfRKbGx1FqvPbpZ6ajh4ddxpXhSxI3VCeb3MsMBuIbiLqX4fQAL3ls/Zwz8tVIITuSwOhYmSEGcpBA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@bufbuild/buf-win32-x64": {
"version": "1.19.0-1",
"resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.19.0-1.tgz",
"integrity": "sha512-futmqgpMQCR1lcAzZJEGjPr7ECw1gYTPIV8crm5SY+iCJ7sOeStOBNt7q5hV4LKmmeWmvm03XIMZPjhQzjH5NQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@bufbuild/connect": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@bufbuild/connect/-/connect-0.9.0.tgz",
"integrity": "sha512-UGOapHlbdbXW9Os08plEuR2k3ZwFWni3BnYVSEPITDTjgEqTagbm6lNWurXM53FDPvueSYYTTJF3Rivhp03xbQ==",
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@bufbuild/connect-web": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@bufbuild/connect-web/-/connect-web-0.9.0.tgz",
"integrity": "sha512-WyYWjPRWceUc/1d5n8oA1NcCni2ND6qj8iXd1Hqy6qkCyo2n/FUSSe3oQuoXYZ9KCUI+5qexHz46n2jtzmFDiQ==",
"dependencies": {
"@bufbuild/connect": "0.9.0"
},
"peerDependencies": {
"@bufbuild/protobuf": "^1.2.0"
}
},
"node_modules/@bufbuild/protobuf": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.2.0.tgz",
"integrity": "sha512-MBVuQMOBHxgGnZ9XCUIi8WOy5O/T4ma3TduCRhRvndv3UDbG9cHgd8h6nOYSGyBYPEvXf1z9nTwhp8mVIDbq2g=="
},
"node_modules/@bufbuild/protoc-gen-connect-es": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protoc-gen-connect-es/-/protoc-gen-connect-es-0.9.0.tgz",
"integrity": "sha512-PiLmuti2hbHiZ0u/frUExq9o+RFHnOOnkgPbFZ0JJd0X4bug7q/LWOPWhGwuLKwiZjO+D7XkdApzvvRXchUlwA==",
"dev": true,
"dependencies": {
"@bufbuild/protobuf": "^1.2.0",
"@bufbuild/protoplugin": "^1.2.0"
},
"bin": {
"protoc-gen-connect-es": "bin/protoc-gen-connect-es"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"@bufbuild/connect": "0.9.0",
"@bufbuild/protoc-gen-es": "^1.2.0"
},
"peerDependenciesMeta": {
"@bufbuild/connect": {
"optional": true
},
"@bufbuild/protoc-gen-es": {
"optional": true
}
}
},
"node_modules/@bufbuild/protoc-gen-es": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protoc-gen-es/-/protoc-gen-es-1.2.0.tgz",
"integrity": "sha512-rdg2+Co4H+cImZ81EEzHLEi9bmzmMnS/bsf7XLHKtWYskj1PZVIalfquQejcSV6eWbdmVGKa29JwI5zEkSmkCQ==",
"dev": true,
"dependencies": {
"@bufbuild/protoplugin": "1.2.0"
},
"bin": {
"protoc-gen-es": "bin/protoc-gen-es"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@bufbuild/protobuf": "1.2.0"
},
"peerDependenciesMeta": {
"@bufbuild/protobuf": {
"optional": true
}
}
},
"node_modules/@bufbuild/protoplugin": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protoplugin/-/protoplugin-1.2.0.tgz",
"integrity": "sha512-TX0mEk+LdIbpK2xr5RqeUswR8jGZs6uCX6Cq8azADj8hhiUr7Xty8agEOU/zR+J71D4dV5SnyEPYyw0nGJ6dGQ==",
"dev": true,
"dependencies": {
"@bufbuild/protobuf": "1.2.0",
"@typescript/vfs": "^1.4.0",
"typescript": "4.5.2"
}
},
"node_modules/@bufbuild/protoplugin/node_modules/typescript": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz",
"integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
"integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
"integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
"integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
"integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
"integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
"integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
"integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
"integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
"integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
"integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
"integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
"cpu": [
"loong64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
"integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
"cpu": [
"mips64el"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
"integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
"cpu": [
"ppc64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
"integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
"cpu": [
"riscv64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
"integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
"cpu": [
"s390x"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
"integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
"integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
"integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
"integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
"integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
"integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
"integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@typescript/vfs": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.4.0.tgz",
"integrity": "sha512-Pood7yv5YWMIX+yCHo176OnF8WUlKGImFG7XlsuH14Zb1YN5+dYD3uUtS7lqZtsH7tAveNUi2NzdpQCN0yRbaw==",
"dev": true,
"dependencies": {
"debug": "^4.1.1"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/esbuild": {
"version": "0.17.19",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
"integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.17.19",
"@esbuild/android-arm64": "0.17.19",
"@esbuild/android-x64": "0.17.19",
"@esbuild/darwin-arm64": "0.17.19",
"@esbuild/darwin-x64": "0.17.19",
"@esbuild/freebsd-arm64": "0.17.19",
"@esbuild/freebsd-x64": "0.17.19",
"@esbuild/linux-arm": "0.17.19",
"@esbuild/linux-arm64": "0.17.19",
"@esbuild/linux-ia32": "0.17.19",
"@esbuild/linux-loong64": "0.17.19",
"@esbuild/linux-mips64el": "0.17.19",
"@esbuild/linux-ppc64": "0.17.19",
"@esbuild/linux-riscv64": "0.17.19",
"@esbuild/linux-s390x": "0.17.19",
"@esbuild/linux-x64": "0.17.19",
"@esbuild/netbsd-x64": "0.17.19",
"@esbuild/openbsd-x64": "0.17.19",
"@esbuild/sunos-x64": "0.17.19",
"@esbuild/win32-arm64": "0.17.19",
"@esbuild/win32-ia32": "0.17.19",
"@esbuild/win32-x64": "0.17.19"
}
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/postcss": {
"version": "8.4.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/rollup": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz",
"integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==",
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=14.18.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/typescript": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=12.20"
}
},
"node_modules/vite": {
"version": "4.3.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
"integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
"dependencies": {
"esbuild": "^0.17.5",
"postcss": "^8.4.23",
"rollup": "^3.21.0"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@types/node": ">= 14",
"less": "*",
"sass": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"sass": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
}
}
}

View file

@ -0,0 +1,35 @@
{
"name": "frontend",
"version": "0.0.1",
"description": "Web frontend SPA to test axum-connect RPCs",
"author": "Alec Thilenius",
"license": "MIT",
"type": "module",
"scripts": {
"dev": "vite --port 3000",
"build": "tsc --noEmit && npx vite build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/AThilenius/axum-connect.git"
},
"keywords": [
"connect-web"
],
"bugs": {
"url": "https://github.com/AThilenius/axum-connect/issues"
},
"homepage": "https://github.com/AThilenius/axum-connect#readme",
"dependencies": {
"@buf/grpc_grpc.bufbuild_connect-es": "^0.9.0-20230516211939-d8bc6b0fb32a.1",
"@bufbuild/connect": "^0.9.0",
"@bufbuild/connect-web": "^0.9.0",
"vite": "^4.3.9"
},
"devDependencies": {
"@bufbuild/buf": "^1.19.0-1",
"@bufbuild/protoc-gen-connect-es": "^0.9.0",
"@bufbuild/protoc-gen-es": "^1.2.0",
"typescript": "^5.0.4"
}
}

View file

@ -0,0 +1,41 @@
import { ConnectError, createPromiseClient } from "@bufbuild/connect";
import { createConnectTransport } from "@bufbuild/connect-web";
import { TestService } from "@buf/grpc_grpc.bufbuild_connect-es/grpc/testing/test_connect";
const client = createPromiseClient(
TestService,
createConnectTransport({
// TODO
baseUrl: "http://localhost:3030",
// baseUrl: config.blink.httpUri,
// interceptors: [authInterceptor],
})
);
async function runTests() {
test("emptyCall", async () => {
await client.emptyCall({});
});
test("unaryCall", async () => {
await client.unaryCall({});
});
}
runTests();
async function test(name: string, test: () => Promise<any>) {
let a: ConnectError;
const div = document.createElement("div");
document.body.appendChild(div);
try {
await test();
console.log(name, "passed");
div.style.color = "green";
div.innerText = `${name} ok`;
} catch (e) {
console.log(name, "failed:", e);
div.style.color = "red";
div.innerText = `${name} failed: ${e}`;
}
}

View file

@ -0,0 +1,35 @@
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"alwaysStrict": true,
"baseUrl": ".",
"declaration": true,
"downlevelIteration": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"lib": ["dom", "dom.iterable", "esnext", "webworker"],
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"paths": { "~/*": ["src/*"] },
"removeComments": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"target": "es5",
"types": ["vite/client"],
"useDefineForClassFields": true
},
"include": ["./src/**/*"],
"exclude": ["./node_modules/**/*"]
}

View file

@ -0,0 +1,11 @@
import { defineConfig } from "vite";
import { resolve } from "path";
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
"~": resolve(__dirname, "./src"),
},
},
});

View file

@ -0,0 +1,29 @@
// This is copied from gRPC's testing Protobuf definitions: https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/empty.proto
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package grpc.testing;
// An empty message that you can re-use to avoid defining duplicated empty
// messages in your project. A typical example is to use it as argument or the
// return value of a service API. For instance:
//
// service Foo {
// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
// };
//
message Empty {}

View file

@ -0,0 +1,284 @@
// This is copied from gRPC's testing Protobuf definitions: https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/messages.proto
// Copyright 2015-2016 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Message definitions to be used by integration test service definitions.
syntax = "proto3";
package grpc.testing;
import "google/protobuf/any.proto";
// TODO(dgq): Go back to using well-known types once
// https://github.com/grpc/grpc/issues/6980 has been fixed.
// import "google/protobuf/wrappers.proto";
message BoolValue {
// The bool value.
bool value = 1;
}
// The type of payload that should be returned.
enum PayloadType {
// Compressable text format.
COMPRESSABLE = 0;
}
// A block of data, to simply increase gRPC message size.
message Payload {
// The type of data in body.
PayloadType type = 1;
// Primary contents of payload.
bytes body = 2;
}
// A protobuf representation for grpc status. This is used by test
// clients to specify a status that the server should attempt to return.
message EchoStatus {
int32 code = 1;
string message = 2;
}
// The type of route that a client took to reach a server w.r.t. gRPCLB.
// The server must fill in "fallback" if it detects that the RPC reached
// the server via the "gRPCLB fallback" path, and "backend" if it detects
// that the RPC reached the server via "gRPCLB backend" path (i.e. if it got
// the address of this server from the gRPCLB server BalanceLoad RPC). Exactly
// how this detection is done is context and server dependent.
enum GrpclbRouteType {
// Server didn't detect the route that a client took to reach it.
GRPCLB_ROUTE_TYPE_UNKNOWN = 0;
// Indicates that a client reached a server via gRPCLB fallback.
GRPCLB_ROUTE_TYPE_FALLBACK = 1;
// Indicates that a client reached a server as a gRPCLB-given backend.
GRPCLB_ROUTE_TYPE_BACKEND = 2;
}
// Unary request.
message SimpleRequest {
// Desired payload type in the response from the server.
// If response_type is RANDOM, server randomly chooses one from other formats.
PayloadType response_type = 1;
// Desired payload size in the response from the server.
int32 response_size = 2;
// Optional input payload sent along with the request.
Payload payload = 3;
// Whether SimpleResponse should include username.
bool fill_username = 4;
// Whether SimpleResponse should include OAuth scope.
bool fill_oauth_scope = 5;
// Whether to request the server to compress the response. This field is
// "nullable" in order to interoperate seamlessly with clients not able to
// implement the full compression tests by introspecting the call to verify
// the response's compression status.
BoolValue response_compressed = 6;
// Whether server should return a given status
EchoStatus response_status = 7;
// Whether the server should expect this request to be compressed.
BoolValue expect_compressed = 8;
// Whether SimpleResponse should include server_id.
bool fill_server_id = 9;
// Whether SimpleResponse should include grpclb_route_type.
bool fill_grpclb_route_type = 10;
}
// Unary response, as configured by the request.
message SimpleResponse {
// Payload to increase message size.
Payload payload = 1;
// The user the request came from, for verifying authentication was
// successful when the client expected it.
string username = 2;
// OAuth scope.
string oauth_scope = 3;
// Server ID. This must be unique among different server instances,
// but the same across all RPC's made to a particular server instance.
string server_id = 4;
// gRPCLB Path.
GrpclbRouteType grpclb_route_type = 5;
// Server hostname.
string hostname = 6;
}
// Client-streaming request.
message StreamingInputCallRequest {
// Optional input payload sent along with the request.
Payload payload = 1;
// Whether the server should expect this request to be compressed. This field
// is "nullable" in order to interoperate seamlessly with servers not able to
// implement the full compression tests by introspecting the call to verify
// the request's compression status.
BoolValue expect_compressed = 2;
// Not expecting any payload from the response.
}
// Client-streaming response.
message StreamingInputCallResponse {
// Aggregated size of payloads received from the client.
int32 aggregated_payload_size = 1;
}
// Configuration for a particular response.
message ResponseParameters {
// Desired payload sizes in responses from the server.
int32 size = 1;
// Desired interval between consecutive responses in the response stream in
// microseconds.
int32 interval_us = 2;
// Whether to request the server to compress the response. This field is
// "nullable" in order to interoperate seamlessly with clients not able to
// implement the full compression tests by introspecting the call to verify
// the response's compression status.
BoolValue compressed = 3;
}
// Server-streaming request.
message StreamingOutputCallRequest {
// Desired payload type in the response from the server.
// If response_type is RANDOM, the payload from each response in the stream
// might be of different types. This is to simulate a mixed type of payload
// stream.
PayloadType response_type = 1;
// Configuration for each expected response message.
repeated ResponseParameters response_parameters = 2;
// Optional input payload sent along with the request.
Payload payload = 3;
// Whether server should return a given status
EchoStatus response_status = 7;
}
// Server-streaming response, as configured by the request and parameters.
message StreamingOutputCallResponse {
// Payload to increase response size.
Payload payload = 1;
}
// For reconnect interop test only.
// Client tells server what reconnection parameters it used.
message ReconnectParams {
int32 max_reconnect_backoff_ms = 1;
}
// For reconnect interop test only.
// Server tells client whether its reconnects are following the spec and the
// reconnect backoffs it saw.
message ReconnectInfo {
bool passed = 1;
repeated int32 backoff_ms = 2;
}
message LoadBalancerStatsRequest {
// Request stats for the next num_rpcs sent by client.
int32 num_rpcs = 1;
// If num_rpcs have not completed within timeout_sec, return partial results.
int32 timeout_sec = 2;
}
message LoadBalancerStatsResponse {
message RpcsByPeer {
// The number of completed RPCs for each peer.
map<string, int32> rpcs_by_peer = 1;
}
// The number of completed RPCs for each peer.
map<string, int32> rpcs_by_peer = 1;
// The number of RPCs that failed to record a remote peer.
int32 num_failures = 2;
map<string, RpcsByPeer> rpcs_by_method = 3;
}
// Request for retrieving a test client's accumulated stats.
message LoadBalancerAccumulatedStatsRequest {}
// Accumulated stats for RPCs sent by a test client.
message LoadBalancerAccumulatedStatsResponse {
// The total number of RPCs have ever issued for each type.
// Deprecated: use stats_per_method.rpcs_started instead.
map<string, int32> num_rpcs_started_by_method = 1 [deprecated = true];
// The total number of RPCs have ever completed successfully for each type.
// Deprecated: use stats_per_method.result instead.
map<string, int32> num_rpcs_succeeded_by_method = 2 [deprecated = true];
// The total number of RPCs have ever failed for each type.
// Deprecated: use stats_per_method.result instead.
map<string, int32> num_rpcs_failed_by_method = 3 [deprecated = true];
message MethodStats {
// The number of RPCs that were started for this method.
int32 rpcs_started = 1;
// The number of RPCs that completed with each status for this method. The
// key is the integral value of a google.rpc.Code; the value is the count.
map<int32, int32> result = 2;
}
// Per-method RPC statistics. The key is the RpcType in string form; e.g.
// 'EMPTY_CALL' or 'UNARY_CALL'
map<string, MethodStats> stats_per_method = 4;
}
// Configurations for a test client.
message ClientConfigureRequest {
// Type of RPCs to send.
enum RpcType {
EMPTY_CALL = 0;
UNARY_CALL = 1;
}
// Metadata to be attached for the given type of RPCs.
message Metadata {
RpcType type = 1;
string key = 2;
string value = 3;
}
// The types of RPCs the client sends.
repeated RpcType types = 1;
// The collection of custom metadata to be attached to RPCs sent by the client.
repeated Metadata metadata = 2;
// The deadline to use, in seconds, for all RPCs. If unset or zero, the
// client will use the default from the command-line.
int32 timeout_sec = 3;
}
// Response for updating a test client's configuration.
message ClientConfigureResponse {}
message ErrorDetail {
string reason = 1;
string domain = 2;
}
message ErrorStatus {
int32 code = 1;
string message = 2;
repeated google.protobuf.Any details = 3;
}

View file

@ -0,0 +1,126 @@
// This is copied from gRPC's testing Protobuf definitions: https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/test.proto
//
// The TestService has been extended to include the following RPCs:
// FailUnaryCall(SimpleRequest) returns (SimpleResponse): this RPC is a unary
// call that always returns a readable non-ASCII error with error details.
// FailStreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse):
// this RPC is a server streaming call that always returns a readable non-ASCII error with error details.
// UnimplementedStreamingOutputCall(grpc.testing.Empty) returns (stream grpc.testing.Empty): this RPC
// is a server streaming call that will not be implemented.
//
// The UnimplementedService has been extended to include the following RPCs:
// UnimplementedStreamingOutputCall(grpc.testing.Empty) returns (stream grpc.testing.Empty): this RPC
// is a server streaming call that will not be implemented.
// Copyright 2015-2016 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// An integration test service that covers all the method signature permutations
// of unary/streaming requests/responses.
syntax = "proto3";
package grpc.testing;
import "grpc/testing/empty.proto";
import "grpc/testing/messages.proto";
// A simple service to test the various types of RPCs and experiment with
// performance with various types of payload.
service TestService {
// One empty request followed by one empty response.
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// One request followed by one response.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by one response. This RPC always fails.
rpc FailUnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by one response. Response has cache control
// headers set such that a caching HTTP proxy (such as GFE) can
// satisfy subsequent requests.
rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse) {
option idempotency_level = NO_SIDE_EFFECTS;
}
// One request followed by a sequence of responses (streamed download).
// The server returns the payload with client desired type and sizes.
rpc StreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse);
// One request followed by a sequence of responses (streamed download).
// The server returns the payload with client desired type and sizes.
// This RPC always responds with an error status.
rpc FailStreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse);
// A sequence of requests followed by one response (streamed upload).
// The server returns the aggregated size of client payload as the result.
rpc StreamingInputCall(stream StreamingInputCallRequest) returns (StreamingInputCallResponse);
// A sequence of requests with each request served by the server immediately.
// As one request could lead to multiple responses, this interface
// demonstrates the idea of full duplexing.
rpc FullDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse);
// A sequence of requests followed by a sequence of responses.
// The server buffers all the client requests and then serves them in order. A
// stream of responses are returned to the client when the server starts with
// first request.
rpc HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse);
// The test server will not implement this method. It will be used
// to test the behavior when clients call unimplemented methods.
rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// The test server will not implement this method. It will be used
// to test the behavior when clients call unimplemented streaming output methods.
rpc UnimplementedStreamingOutputCall(grpc.testing.Empty) returns (stream grpc.testing.Empty);
}
// A simple service NOT implemented at servers so clients can test for
// that case.
service UnimplementedService {
// A call that no server should implement
rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// A call that no server should implement
rpc UnimplementedStreamingOutputCall(grpc.testing.Empty) returns (stream grpc.testing.Empty);
}
// A service used to control reconnect server.
service ReconnectService {
rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty);
rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo);
}
// A service used to obtain stats for verifying LB behavior.
service LoadBalancerStatsService {
// Gets the backend distribution for RPCs sent by a test client.
rpc GetClientStats(LoadBalancerStatsRequest) returns (LoadBalancerStatsResponse) {}
// Gets the accumulated stats for RPCs sent by a test client.
rpc GetClientAccumulatedStats(LoadBalancerAccumulatedStatsRequest) returns (LoadBalancerAccumulatedStatsResponse) {}
}
// A service to remotely control health status of an xDS test server.
service XdsUpdateHealthService {
rpc SetServing(grpc.testing.Empty) returns (grpc.testing.Empty);
rpc SetNotServing(grpc.testing.Empty) returns (grpc.testing.Empty);
}
// A service to dynamically update the configuration of an xDS test client.
service XdsUpdateClientConfigureService {
// Update the tes client's configuration.
rpc Configure(ClientConfigureRequest) returns (ClientConfigureResponse);
}

View file

@ -0,0 +1,150 @@
use std::net::SocketAddr;
use axum::{routing::get, Router};
use axum_connect::prelude::*;
use tower_http::cors::CorsLayer;
use proto::grpc::testing::*;
mod proto {
pub mod grpc {
pub mod testing {
include!(concat!(env!("OUT_DIR"), "/grpc.testing.rs"));
}
}
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/status", get(status))
.rpc(TestService::empty_call(empty_call))
.rpc(TestService::unary_call(unary_call))
.rpc(TestService::fail_unary_call(fail_unary_call));
let addr = SocketAddr::from(([127, 0, 0, 1], 3030));
println!("listening on http://{}", addr);
axum::Server::bind(&addr)
.serve(app.layer(CorsLayer::very_permissive()).into_make_service())
.await
.unwrap();
}
async fn status() -> &'static str {
"OK\n"
}
async fn empty_call(_: Empty) -> Empty {
Empty {}
}
async fn unary_call(request: SimpleRequest) -> Result<SimpleResponse, RpcError> {
// if leadingMetadata := request.Header().Values(leadingMetadataKey); len(leadingMetadata) != 0 {
// for _, value := range leadingMetadata {
// response.Header().Add(leadingMetadataKey, value)
// }
// }
// if trailingMetadata := request.Header().Values(trailingMetadataKey); len(trailingMetadata) != 0 {
// for _, value := range trailingMetadata {
// decodedTrailingMetadata, err := connect.DecodeBinaryHeader(value)
// if err != nil {
// return nil, err
// }
// response.Trailer().Add(trailingMetadataKey, connect.EncodeBinaryHeader(decodedTrailingMetadata))
// }
// }
// response.Header().Set("Request-Protocol", request.Peer().Protocol)
// return response, nil
if let Some(response_status) = &request.response_status {
if response_status.code != 0 {
return Err(RpcError {
code: rpc_error_code_from_i32(response_status.code)
.unwrap()
.to_owned(),
message: response_status.message.clone(),
details: vec![],
});
}
}
let payload = new_server_payload(request.response_type(), request.response_size)?;
let response = SimpleResponse {
payload: Some(payload),
..Default::default()
};
Ok(response)
}
async fn fail_unary_call(_: SimpleRequest) -> RpcError {
RpcError {
code: RpcErrorCode::ResourceExhausted,
message: "soirée 🎉".to_owned(),
details: vec![
// ("reason", ErrorDetail {
// }).into(),
// ("domain", "connect-crosstest").into(),
],
}
}
fn new_server_payload(payload_type: PayloadType, size: i32) -> Result<Payload, RpcError> {
if size < 0 {
return Err(RpcError::new(
RpcErrorCode::Internal,
format!("requested a response with invalid length {}", size),
));
}
let body = vec![0; size as usize];
match payload_type {
PayloadType::Compressable => Ok(Payload {
r#type: PayloadType::Compressable as i32,
body,
}),
}
}
pub fn rpc_error_code_from_i32(num: i32) -> Option<RpcErrorCode> {
match num {
1 => Some(RpcErrorCode::Canceled),
2 => Some(RpcErrorCode::Unknown),
3 => Some(RpcErrorCode::InvalidArgument),
4 => Some(RpcErrorCode::DeadlineExceeded),
5 => Some(RpcErrorCode::NotFound),
6 => Some(RpcErrorCode::AlreadyExists),
7 => Some(RpcErrorCode::PermissionDenied),
8 => Some(RpcErrorCode::ResourceExhausted),
9 => Some(RpcErrorCode::FailedPrecondition),
10 => Some(RpcErrorCode::Aborted),
11 => Some(RpcErrorCode::OutOfRange),
12 => Some(RpcErrorCode::Unimplemented),
13 => Some(RpcErrorCode::Internal),
14 => Some(RpcErrorCode::Unavailable),
15 => Some(RpcErrorCode::DataLoss),
16 => Some(RpcErrorCode::Unauthenticated),
_ => None,
}
}
pub fn i32_to_rpc_error_code(rpc_error_code: RpcErrorCode) -> i32 {
match rpc_error_code {
RpcErrorCode::Canceled => 1,
RpcErrorCode::Unknown => 2,
RpcErrorCode::InvalidArgument => 3,
RpcErrorCode::DeadlineExceeded => 4,
RpcErrorCode::NotFound => 5,
RpcErrorCode::AlreadyExists => 6,
RpcErrorCode::PermissionDenied => 7,
RpcErrorCode::ResourceExhausted => 8,
RpcErrorCode::FailedPrecondition => 9,
RpcErrorCode::Aborted => 10,
RpcErrorCode::OutOfRange => 11,
RpcErrorCode::Unimplemented => 12,
RpcErrorCode::Internal => 13,
RpcErrorCode::Unavailable => 14,
RpcErrorCode::DataLoss => 15,
RpcErrorCode::Unauthenticated => 16,
}
}