starpc 0.30.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +14 -16
- package/README.md +12 -2
- package/cmd/protoc-gen-es-starpc/plugin.ts +24 -0
- package/cmd/protoc-gen-es-starpc/protoc-gen-es-starpc +2 -0
- package/cmd/protoc-gen-es-starpc/protoc-gen-es-starpc.ts +19 -0
- package/cmd/protoc-gen-es-starpc/typescript.ts +183 -0
- package/dist/cmd/protoc-gen-es-starpc/plugin.d.ts +1 -0
- package/dist/cmd/protoc-gen-es-starpc/plugin.js +22 -0
- package/dist/cmd/protoc-gen-es-starpc/protoc-gen-es-starpc.js +17 -0
- package/dist/cmd/protoc-gen-es-starpc/typescript.d.ts +2 -0
- package/dist/cmd/protoc-gen-es-starpc/typescript.js +167 -0
- package/dist/e2e/mock/mock_pb.d.ts +21 -0
- package/dist/e2e/mock/mock_pb.js +36 -0
- package/dist/e2e/mock/mock_srpc.pb.d.ts +52 -0
- package/dist/e2e/mock/mock_srpc.pb.js +44 -0
- package/dist/echo/EchoerClientImpl.d.ts +0 -0
- package/dist/echo/EchoerClientImpl.js +1 -0
- package/dist/echo/client-test.js +8 -6
- package/dist/echo/echo_pb.d.ts +21 -0
- package/dist/echo/echo_pb.js +36 -0
- package/dist/echo/echo_srpc.pb.d.ts +145 -0
- package/dist/echo/echo_srpc.pb.js +131 -0
- package/dist/echo/index.d.ts +2 -1
- package/dist/echo/index.js +2 -1
- package/dist/echo/server.d.ts +10 -7
- package/dist/echo/server.js +2 -3
- package/dist/package.json +100 -0
- package/dist/rpcstream/index.d.ts +1 -1
- package/dist/rpcstream/index.js +1 -1
- package/dist/rpcstream/rpcstream.d.ts +6 -4
- package/dist/rpcstream/rpcstream.js +17 -15
- package/dist/rpcstream/rpcstream_pb.d.ts +92 -0
- package/dist/rpcstream/rpcstream_pb.js +117 -0
- package/dist/srpc/client-rpc.d.ts +1 -1
- package/dist/srpc/client-rpc.js +2 -2
- package/dist/srpc/client.d.ts +2 -2
- package/dist/srpc/common-rpc.d.ts +7 -6
- package/dist/srpc/common-rpc.js +10 -10
- package/dist/srpc/definition.d.ts +12 -12
- package/dist/srpc/handler.d.ts +2 -2
- package/dist/srpc/handler.js +1 -1
- package/dist/srpc/index.d.ts +4 -3
- package/dist/srpc/index.js +2 -2
- package/dist/srpc/invoker.d.ts +4 -3
- package/dist/srpc/invoker.js +7 -4
- package/dist/srpc/message.d.ts +7 -11
- package/dist/srpc/message.js +8 -14
- package/dist/srpc/packet.d.ts +1 -1
- package/dist/srpc/packet.js +1 -1
- package/dist/srpc/{ts-proto-rpc.d.ts → proto-rpc.d.ts} +1 -1
- package/dist/srpc/proto-rpc.js +1 -0
- package/dist/srpc/pushable.d.ts +2 -0
- package/dist/srpc/pushable.js +5 -0
- package/dist/srpc/rpcproto_pb.d.ts +132 -0
- package/dist/srpc/rpcproto_pb.js +165 -0
- package/dist/srpc/server-rpc.d.ts +1 -1
- package/dist/srpc/stream.d.ts +1 -1
- package/e2e/mock/mock.pb.go +22 -1
- package/e2e/mock/mock_pb.ts +64 -0
- package/e2e/mock/mock_srpc.pb.ts +77 -0
- package/echo/EchoerClientImpl.ts +0 -0
- package/echo/client-test.ts +10 -6
- package/echo/echo.pb.go +22 -1
- package/echo/echo_pb.ts +64 -0
- package/echo/echo_srpc.pb.ts +244 -0
- package/echo/index.ts +4 -3
- package/echo/server.ts +15 -13
- package/go.mod +3 -3
- package/go.sum +6 -6
- package/integration/integration.bash +11 -3
- package/package.json +17 -14
- package/srpc/client-rpc.ts +5 -4
- package/srpc/client.ts +2 -2
- package/srpc/common-rpc.ts +20 -19
- package/srpc/definition.ts +35 -24
- package/srpc/handler.ts +7 -9
- package/srpc/index.ts +8 -3
- package/srpc/invoker.ts +34 -17
- package/srpc/message.ts +25 -39
- package/srpc/packet.ts +1 -1
- package/srpc/{ts-proto-rpc.ts → proto-rpc.ts} +3 -2
- package/srpc/pushable.ts +9 -1
- package/srpc/rpcproto.pb.go +102 -1
- package/srpc/rpcproto_pb.ts +265 -0
- package/srpc/server-rpc.ts +1 -1
- package/srpc/stream.ts +1 -1
- package/dist/e2e/mock/mock.pb.d.ts +0 -110
- package/dist/e2e/mock/mock.pb.js +0 -117
- package/dist/echo/echo.pb.d.ts +0 -494
- package/dist/echo/echo.pb.js +0 -178
- package/dist/rpcstream/rpcstream.pb.d.ts +0 -195
- package/dist/rpcstream/rpcstream.pb.js +0 -331
- package/dist/srpc/rpcproto.pb.d.ts +0 -291
- package/dist/srpc/rpcproto.pb.js +0 -448
- package/e2e/mock/mock.pb.ts +0 -200
- package/echo/echo.pb.ts +0 -335
- package/srpc/rpcproto.pb.ts +0 -608
- /package/dist/{srpc/ts-proto-rpc.js → cmd/protoc-gen-es-starpc/protoc-gen-es-starpc.d.ts} +0 -0
package/Makefile
CHANGED
|
@@ -77,27 +77,25 @@ genproto: vendor node_modules $(GOIMPORTS) $(PROTOWRAP) $(PROTOC_GEN_GO) $(PROTO
|
|
|
77
77
|
set -eo pipefail; \
|
|
78
78
|
export PROJECT=$$(go list -m); \
|
|
79
79
|
export PATH=$$(pwd)/hack/bin:$${PATH}; \
|
|
80
|
-
|
|
80
|
+
export OUT=$$(pwd)/vendor; \
|
|
81
|
+
mkdir -p $${OUT}/$$(dirname $${PROJECT}); \
|
|
81
82
|
rm $$(pwd)/vendor/$${PROJECT} || true; \
|
|
82
83
|
ln -s $$(pwd) $$(pwd)/vendor/$${PROJECT} ; \
|
|
83
84
|
protogen() { \
|
|
84
85
|
$(PROTOWRAP) \
|
|
85
|
-
-I $$
|
|
86
|
-
--plugin=./node_modules/.bin/protoc-gen-
|
|
87
|
-
--
|
|
86
|
+
-I $${OUT} \
|
|
87
|
+
--plugin=./node_modules/.bin/protoc-gen-es \
|
|
88
|
+
--plugin=./cmd/protoc-gen-es-starpc/protoc-gen-es-starpc \
|
|
89
|
+
--go-lite_out=$${OUT} \
|
|
88
90
|
--go-lite_opt=features=marshal+unmarshal+size+equal+json+clone \
|
|
89
|
-
--go-starpc_out=$$
|
|
90
|
-
--
|
|
91
|
-
--
|
|
92
|
-
--
|
|
93
|
-
--
|
|
94
|
-
--
|
|
95
|
-
--
|
|
96
|
-
--
|
|
97
|
-
--ts_proto_opt=useAbortSignal=true \
|
|
98
|
-
--ts_proto_opt=useAsyncIterable=true \
|
|
99
|
-
--ts_proto_opt=useDate=true \
|
|
100
|
-
--proto_path $$(pwd)/vendor \
|
|
91
|
+
--go-starpc_out=$${OUT} \
|
|
92
|
+
--es_out=$${OUT} \
|
|
93
|
+
--es_opt target=ts \
|
|
94
|
+
--es_opt ts_nocheck=false \
|
|
95
|
+
--es-starpc_out=$${OUT} \
|
|
96
|
+
--es-starpc_opt target=ts \
|
|
97
|
+
--es-starpc_opt ts_nocheck=false \
|
|
98
|
+
--proto_path $${OUT} \
|
|
101
99
|
--print_structure \
|
|
102
100
|
--only_specified_files \
|
|
103
101
|
$$(\
|
package/README.md
CHANGED
|
@@ -26,6 +26,10 @@ Supports **client-to-server and bidirectional streaming** in the web browser.
|
|
|
26
26
|
The library leverages libp2p streams with `@chainsafe/libp2p-yamux` to
|
|
27
27
|
coordinate balancing many ongoing RPCs over a single connection.
|
|
28
28
|
|
|
29
|
+
starpc uses [protobuf-go-lite] to generate reflection-free Go code.
|
|
30
|
+
|
|
31
|
+
[protobuf-go-lite]: https://github.com/aperturerobotics/protobuf-go-lite
|
|
32
|
+
|
|
29
33
|
## Usage
|
|
30
34
|
|
|
31
35
|
Start with the [protobuf-project] template repository on the "starpc" branch.
|
|
@@ -121,12 +125,12 @@ This examples demonstrates connecting to a WebSocket server:
|
|
|
121
125
|
|
|
122
126
|
```typescript
|
|
123
127
|
import { WebSocketConn } from 'srpc'
|
|
124
|
-
import {
|
|
128
|
+
import { EchoerClient } from 'srpc/echo'
|
|
125
129
|
|
|
126
130
|
const ws = new WebSocket('ws://localhost:5000/demo')
|
|
127
131
|
const channel = new WebSocketConn(ws)
|
|
128
132
|
const client = channel.buildClient()
|
|
129
|
-
const demoServiceClient = new
|
|
133
|
+
const demoServiceClient = new EchoerClient(client)
|
|
130
134
|
|
|
131
135
|
const result = await demoServiceClient.Echo({
|
|
132
136
|
body: "Hello world!"
|
|
@@ -195,6 +199,12 @@ Uses [vtprotobuf] to generate Protobuf marshal / unmarshal code.
|
|
|
195
199
|
|
|
196
200
|
[vtprotobuf]: https://github.com/planetscale/vtprotobuf
|
|
197
201
|
|
|
202
|
+
Uses [protobuf-es] to serialize Protobuf in TypeScript.
|
|
203
|
+
|
|
204
|
+
[protobuf-es]: https://github.com/bufbuild/protobuf-es
|
|
205
|
+
|
|
206
|
+
`protoc-gen-es-starpc` is a heavily modified version of `protoc-gen-connect-es`.
|
|
207
|
+
|
|
198
208
|
## Developing on MacOS
|
|
199
209
|
|
|
200
210
|
On MacOS, some homebrew packages are required for `yarn gen`:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright 2024 Aperture Robotics, LLC.
|
|
2
|
+
// Copyright 2021-2024 The Connect Authors
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
|
|
16
|
+
import { createEcmaScriptPlugin } from '@bufbuild/protoplugin'
|
|
17
|
+
import { generateTs } from './typescript.js'
|
|
18
|
+
import { version } from '../../package.json'
|
|
19
|
+
|
|
20
|
+
export const protocGenEsStarpc = createEcmaScriptPlugin({
|
|
21
|
+
name: 'protoc-gen-es-starpc',
|
|
22
|
+
version: `v${String(version)}`,
|
|
23
|
+
generateTs,
|
|
24
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright 2024 Aperture Robotics, LLC.
|
|
2
|
+
// Copyright 2021-2024 The Connect Authors
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
|
|
16
|
+
import { runNodeJs } from '@bufbuild/protoplugin'
|
|
17
|
+
import { protocGenEsStarpc } from './plugin.js'
|
|
18
|
+
|
|
19
|
+
runNodeJs(protocGenEsStarpc)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// Copyright 2024 Aperture Robotics, LLC.
|
|
2
|
+
// Copyright 2021-2024 The Connect Authors
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
|
|
16
|
+
import type { DescService } from '@bufbuild/protobuf'
|
|
17
|
+
import { MethodIdempotency, MethodKind } from '@bufbuild/protobuf'
|
|
18
|
+
import type { GeneratedFile, Schema } from '@bufbuild/protoplugin/ecmascript'
|
|
19
|
+
import { createImportSymbol, localName } from '@bufbuild/protoplugin/ecmascript'
|
|
20
|
+
|
|
21
|
+
export function generateTs(schema: Schema) {
|
|
22
|
+
for (const protoFile of schema.files) {
|
|
23
|
+
const file = schema.generateFile(protoFile.name + '_srpc.pb.ts')
|
|
24
|
+
file.preamble(protoFile)
|
|
25
|
+
for (const service of protoFile.services) {
|
|
26
|
+
generateService(schema, file, service)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// prettier-ignore
|
|
32
|
+
function generateService(
|
|
33
|
+
schema: Schema,
|
|
34
|
+
f: GeneratedFile,
|
|
35
|
+
service: DescService
|
|
36
|
+
) {
|
|
37
|
+
const { MethodKind: rtMethodKind, MethodIdempotency: rtMethodIdempotency, PartialMessage } =
|
|
38
|
+
schema.runtime;
|
|
39
|
+
const MessageStream = createImportSymbol("MessageStream", "starpc")
|
|
40
|
+
|
|
41
|
+
// NOTE: This matches generateService from @connectrpc/protoc-gen-connect-es.
|
|
42
|
+
f.print(f.jsDoc(service));
|
|
43
|
+
f.print(f.exportDecl("const", localName(service)), "Definition = {");
|
|
44
|
+
f.print(` typeName: `, f.string(service.typeName), `,`);
|
|
45
|
+
f.print(" methods: {");
|
|
46
|
+
for (const method of service.methods) {
|
|
47
|
+
f.print(f.jsDoc(method, " "));
|
|
48
|
+
f.print(" ", method.name, ": {");
|
|
49
|
+
f.print(` name: `, f.string(method.name), `,`);
|
|
50
|
+
f.print(" I: ", method.input, ",");
|
|
51
|
+
f.print(" O: ", method.output, ",");
|
|
52
|
+
f.print(
|
|
53
|
+
" kind: ",
|
|
54
|
+
rtMethodKind,
|
|
55
|
+
".",
|
|
56
|
+
MethodKind[method.methodKind],
|
|
57
|
+
","
|
|
58
|
+
);
|
|
59
|
+
if (method.idempotency !== undefined) {
|
|
60
|
+
f.print(
|
|
61
|
+
" idempotency: ",
|
|
62
|
+
rtMethodIdempotency,
|
|
63
|
+
".",
|
|
64
|
+
MethodIdempotency[method.idempotency],
|
|
65
|
+
","
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
// In case we start supporting options, we have to surface them here
|
|
69
|
+
f.print(" },");
|
|
70
|
+
}
|
|
71
|
+
f.print(" }");
|
|
72
|
+
f.print("} as const;");
|
|
73
|
+
f.print();
|
|
74
|
+
|
|
75
|
+
// Generate the service interface
|
|
76
|
+
f.print(f.jsDoc(service));
|
|
77
|
+
f.print("export interface ", localName(service), " {");
|
|
78
|
+
for (const method of service.methods) {
|
|
79
|
+
f.print(f.jsDoc(method, " "));
|
|
80
|
+
f.print(" ", method.name, "(");
|
|
81
|
+
if (method.methodKind === MethodKind.Unary) {
|
|
82
|
+
f.print("request: ", PartialMessage, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
83
|
+
} else if (method.methodKind === MethodKind.ServerStreaming) {
|
|
84
|
+
f.print("request: ", PartialMessage, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
85
|
+
} else if (method.methodKind === MethodKind.ClientStreaming) {
|
|
86
|
+
f.print("request: ", MessageStream, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
87
|
+
} else if (method.methodKind === MethodKind.BiDiStreaming) {
|
|
88
|
+
f.print("request: ", MessageStream, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
89
|
+
}
|
|
90
|
+
f.print("): ");
|
|
91
|
+
if (method.methodKind === MethodKind.Unary) {
|
|
92
|
+
f.print("Promise<", PartialMessage, "<", method.output, ">>");
|
|
93
|
+
} else if (method.methodKind === MethodKind.ServerStreaming) {
|
|
94
|
+
f.print(MessageStream, "<", method.output, ">");
|
|
95
|
+
} else if (method.methodKind === MethodKind.ClientStreaming) {
|
|
96
|
+
f.print("Promise<", PartialMessage, "<", method.output, ">>");
|
|
97
|
+
} else if (method.methodKind === MethodKind.BiDiStreaming) {
|
|
98
|
+
f.print(MessageStream, "<", method.output, ">");
|
|
99
|
+
}
|
|
100
|
+
f.print();
|
|
101
|
+
}
|
|
102
|
+
f.print("}");
|
|
103
|
+
f.print();
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
// Generate the service name constant
|
|
107
|
+
f.print("export const ", localName(service), "ServiceName = ", localName(service), "Definition.typeName");
|
|
108
|
+
f.print();
|
|
109
|
+
|
|
110
|
+
// Generate the client implementation
|
|
111
|
+
f.print("export class ", localName(service), "Client implements ", localName(service), " {");
|
|
112
|
+
f.print(" private readonly rpc: ", createImportSymbol("ProtoRpc", "starpc"));
|
|
113
|
+
f.print(" private readonly service: string");
|
|
114
|
+
f.print(" constructor(rpc: ProtoRpc, opts?: { service?: string }) {");
|
|
115
|
+
f.print(" this.service = opts?.service || ", localName(service), "ServiceName");
|
|
116
|
+
f.print(" this.rpc = rpc");
|
|
117
|
+
for (const method of service.methods) {
|
|
118
|
+
f.print(" this.", method.name, " = this.", method.name, ".bind(this)");
|
|
119
|
+
}
|
|
120
|
+
f.print(" }");
|
|
121
|
+
|
|
122
|
+
const buildDecodeMessageTransformSymbol = createImportSymbol("buildDecodeMessageTransform", "starpc")
|
|
123
|
+
const buildEncodeMessageTransformSymbol = createImportSymbol("buildEncodeMessageTransform", "starpc")
|
|
124
|
+
for (const method of service.methods) {
|
|
125
|
+
f.print(f.jsDoc(method, " "));
|
|
126
|
+
f.print(" ", method.methodKind === MethodKind.Unary || method.methodKind === MethodKind.ClientStreaming ? "async " : "", method.name, "(");
|
|
127
|
+
if (method.methodKind === MethodKind.Unary) {
|
|
128
|
+
f.print("request: ", PartialMessage, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
129
|
+
} else if (method.methodKind === MethodKind.ServerStreaming) {
|
|
130
|
+
f.print("request: ", PartialMessage, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
131
|
+
} else if (method.methodKind === MethodKind.ClientStreaming) {
|
|
132
|
+
f.print("request: ", MessageStream, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
133
|
+
} else if (method.methodKind === MethodKind.BiDiStreaming) {
|
|
134
|
+
f.print("request: ", MessageStream, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
135
|
+
}
|
|
136
|
+
f.print("): ");
|
|
137
|
+
if (method.methodKind === MethodKind.Unary) {
|
|
138
|
+
f.print("Promise<", PartialMessage, "<", method.output, ">> {");
|
|
139
|
+
f.print(" const requestMsg = new ", method.input, "(request)");
|
|
140
|
+
f.print(" const result = await this.rpc.request(");
|
|
141
|
+
f.print(" this.service,");
|
|
142
|
+
f.print(" ", localName(service), "Definition.methods.", method.name, ".name,");
|
|
143
|
+
f.print(" requestMsg.toBinary(),");
|
|
144
|
+
f.print(" abortSignal || undefined,");
|
|
145
|
+
f.print(" )");
|
|
146
|
+
f.print(" return ", method.output, ".fromBinary(result)");
|
|
147
|
+
f.print(" }");
|
|
148
|
+
} else if (method.methodKind === MethodKind.ServerStreaming) {
|
|
149
|
+
f.print(MessageStream, "<", method.output, "> {");
|
|
150
|
+
f.print(" const requestMsg = new ", method.input, "(request)");
|
|
151
|
+
f.print(" const result = this.rpc.serverStreamingRequest(");
|
|
152
|
+
f.print(" this.service,");
|
|
153
|
+
f.print(" ", localName(service), "Definition.methods.", method.name, ".name,");
|
|
154
|
+
f.print(" requestMsg.toBinary(),");
|
|
155
|
+
f.print(" abortSignal || undefined,");
|
|
156
|
+
f.print(" )");
|
|
157
|
+
f.print(" return ", buildDecodeMessageTransformSymbol, "(", method.output, ")(result)");
|
|
158
|
+
f.print(" }");
|
|
159
|
+
} else if (method.methodKind === MethodKind.ClientStreaming) {
|
|
160
|
+
f.print("Promise<", PartialMessage, "<", method.output, ">> {");
|
|
161
|
+
f.print(" const result = await this.rpc.clientStreamingRequest(");
|
|
162
|
+
f.print(" this.service,");
|
|
163
|
+
f.print(" ", localName(service), "Definition.methods.", method.name, ".name,");
|
|
164
|
+
f.print(" ", buildEncodeMessageTransformSymbol, "(", method.input, ")(request),");
|
|
165
|
+
f.print(" abortSignal || undefined,");
|
|
166
|
+
f.print(" )");
|
|
167
|
+
f.print(" return ", method.output, ".fromBinary(result)");
|
|
168
|
+
f.print(" }");
|
|
169
|
+
} else if (method.methodKind === MethodKind.BiDiStreaming) {
|
|
170
|
+
f.print(MessageStream, "<", method.output, "> {");
|
|
171
|
+
f.print(" const result = this.rpc.bidirectionalStreamingRequest(");
|
|
172
|
+
f.print(" this.service,");
|
|
173
|
+
f.print(" ", localName(service), "Definition.methods.", method.name, ".name,");
|
|
174
|
+
f.print(" ", buildEncodeMessageTransformSymbol, "(", method.input, ")(request),");
|
|
175
|
+
f.print(" abortSignal || undefined,");
|
|
176
|
+
f.print(" )");
|
|
177
|
+
f.print(" return ", buildDecodeMessageTransformSymbol, "(", method.output, ")(result)");
|
|
178
|
+
f.print(" }");
|
|
179
|
+
}
|
|
180
|
+
f.print();
|
|
181
|
+
}
|
|
182
|
+
f.print("}");
|
|
183
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const protocGenEsStarpc: import("@bufbuild/protoplugin").Plugin;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright 2024 Aperture Robotics, LLC.
|
|
2
|
+
// Copyright 2021-2024 The Connect Authors
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
import { createEcmaScriptPlugin } from '@bufbuild/protoplugin';
|
|
16
|
+
import { generateTs } from './typescript.js';
|
|
17
|
+
import { version } from '../../package.json';
|
|
18
|
+
export const protocGenEsStarpc = createEcmaScriptPlugin({
|
|
19
|
+
name: 'protoc-gen-es-starpc',
|
|
20
|
+
version: `v${String(version)}`,
|
|
21
|
+
generateTs,
|
|
22
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Copyright 2024 Aperture Robotics, LLC.
|
|
2
|
+
// Copyright 2021-2024 The Connect Authors
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
import { runNodeJs } from '@bufbuild/protoplugin';
|
|
16
|
+
import { protocGenEsStarpc } from './plugin.js';
|
|
17
|
+
runNodeJs(protocGenEsStarpc);
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// Copyright 2024 Aperture Robotics, LLC.
|
|
2
|
+
// Copyright 2021-2024 The Connect Authors
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
import { MethodIdempotency, MethodKind } from '@bufbuild/protobuf';
|
|
16
|
+
import { createImportSymbol, localName } from '@bufbuild/protoplugin/ecmascript';
|
|
17
|
+
export function generateTs(schema) {
|
|
18
|
+
for (const protoFile of schema.files) {
|
|
19
|
+
const file = schema.generateFile(protoFile.name + '_srpc.pb.ts');
|
|
20
|
+
file.preamble(protoFile);
|
|
21
|
+
for (const service of protoFile.services) {
|
|
22
|
+
generateService(schema, file, service);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// prettier-ignore
|
|
27
|
+
function generateService(schema, f, service) {
|
|
28
|
+
const { MethodKind: rtMethodKind, MethodIdempotency: rtMethodIdempotency, PartialMessage } = schema.runtime;
|
|
29
|
+
const MessageStream = createImportSymbol("MessageStream", "starpc");
|
|
30
|
+
// NOTE: This matches generateService from @connectrpc/protoc-gen-connect-es.
|
|
31
|
+
f.print(f.jsDoc(service));
|
|
32
|
+
f.print(f.exportDecl("const", localName(service)), "Definition = {");
|
|
33
|
+
f.print(` typeName: `, f.string(service.typeName), `,`);
|
|
34
|
+
f.print(" methods: {");
|
|
35
|
+
for (const method of service.methods) {
|
|
36
|
+
f.print(f.jsDoc(method, " "));
|
|
37
|
+
f.print(" ", method.name, ": {");
|
|
38
|
+
f.print(` name: `, f.string(method.name), `,`);
|
|
39
|
+
f.print(" I: ", method.input, ",");
|
|
40
|
+
f.print(" O: ", method.output, ",");
|
|
41
|
+
f.print(" kind: ", rtMethodKind, ".", MethodKind[method.methodKind], ",");
|
|
42
|
+
if (method.idempotency !== undefined) {
|
|
43
|
+
f.print(" idempotency: ", rtMethodIdempotency, ".", MethodIdempotency[method.idempotency], ",");
|
|
44
|
+
}
|
|
45
|
+
// In case we start supporting options, we have to surface them here
|
|
46
|
+
f.print(" },");
|
|
47
|
+
}
|
|
48
|
+
f.print(" }");
|
|
49
|
+
f.print("} as const;");
|
|
50
|
+
f.print();
|
|
51
|
+
// Generate the service interface
|
|
52
|
+
f.print(f.jsDoc(service));
|
|
53
|
+
f.print("export interface ", localName(service), " {");
|
|
54
|
+
for (const method of service.methods) {
|
|
55
|
+
f.print(f.jsDoc(method, " "));
|
|
56
|
+
f.print(" ", method.name, "(");
|
|
57
|
+
if (method.methodKind === MethodKind.Unary) {
|
|
58
|
+
f.print("request: ", PartialMessage, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
59
|
+
}
|
|
60
|
+
else if (method.methodKind === MethodKind.ServerStreaming) {
|
|
61
|
+
f.print("request: ", PartialMessage, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
62
|
+
}
|
|
63
|
+
else if (method.methodKind === MethodKind.ClientStreaming) {
|
|
64
|
+
f.print("request: ", MessageStream, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
65
|
+
}
|
|
66
|
+
else if (method.methodKind === MethodKind.BiDiStreaming) {
|
|
67
|
+
f.print("request: ", MessageStream, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
68
|
+
}
|
|
69
|
+
f.print("): ");
|
|
70
|
+
if (method.methodKind === MethodKind.Unary) {
|
|
71
|
+
f.print("Promise<", PartialMessage, "<", method.output, ">>");
|
|
72
|
+
}
|
|
73
|
+
else if (method.methodKind === MethodKind.ServerStreaming) {
|
|
74
|
+
f.print(MessageStream, "<", method.output, ">");
|
|
75
|
+
}
|
|
76
|
+
else if (method.methodKind === MethodKind.ClientStreaming) {
|
|
77
|
+
f.print("Promise<", PartialMessage, "<", method.output, ">>");
|
|
78
|
+
}
|
|
79
|
+
else if (method.methodKind === MethodKind.BiDiStreaming) {
|
|
80
|
+
f.print(MessageStream, "<", method.output, ">");
|
|
81
|
+
}
|
|
82
|
+
f.print();
|
|
83
|
+
}
|
|
84
|
+
f.print("}");
|
|
85
|
+
f.print();
|
|
86
|
+
// Generate the service name constant
|
|
87
|
+
f.print("export const ", localName(service), "ServiceName = ", localName(service), "Definition.typeName");
|
|
88
|
+
f.print();
|
|
89
|
+
// Generate the client implementation
|
|
90
|
+
f.print("export class ", localName(service), "Client implements ", localName(service), " {");
|
|
91
|
+
f.print(" private readonly rpc: ", createImportSymbol("ProtoRpc", "starpc"));
|
|
92
|
+
f.print(" private readonly service: string");
|
|
93
|
+
f.print(" constructor(rpc: ProtoRpc, opts?: { service?: string }) {");
|
|
94
|
+
f.print(" this.service = opts?.service || ", localName(service), "ServiceName");
|
|
95
|
+
f.print(" this.rpc = rpc");
|
|
96
|
+
for (const method of service.methods) {
|
|
97
|
+
f.print(" this.", method.name, " = this.", method.name, ".bind(this)");
|
|
98
|
+
}
|
|
99
|
+
f.print(" }");
|
|
100
|
+
const buildDecodeMessageTransformSymbol = createImportSymbol("buildDecodeMessageTransform", "starpc");
|
|
101
|
+
const buildEncodeMessageTransformSymbol = createImportSymbol("buildEncodeMessageTransform", "starpc");
|
|
102
|
+
for (const method of service.methods) {
|
|
103
|
+
f.print(f.jsDoc(method, " "));
|
|
104
|
+
f.print(" ", method.methodKind === MethodKind.Unary || method.methodKind === MethodKind.ClientStreaming ? "async " : "", method.name, "(");
|
|
105
|
+
if (method.methodKind === MethodKind.Unary) {
|
|
106
|
+
f.print("request: ", PartialMessage, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
107
|
+
}
|
|
108
|
+
else if (method.methodKind === MethodKind.ServerStreaming) {
|
|
109
|
+
f.print("request: ", PartialMessage, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
110
|
+
}
|
|
111
|
+
else if (method.methodKind === MethodKind.ClientStreaming) {
|
|
112
|
+
f.print("request: ", MessageStream, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
113
|
+
}
|
|
114
|
+
else if (method.methodKind === MethodKind.BiDiStreaming) {
|
|
115
|
+
f.print("request: ", MessageStream, "<", method.input, ">, abortSignal?: AbortSignal");
|
|
116
|
+
}
|
|
117
|
+
f.print("): ");
|
|
118
|
+
if (method.methodKind === MethodKind.Unary) {
|
|
119
|
+
f.print("Promise<", PartialMessage, "<", method.output, ">> {");
|
|
120
|
+
f.print(" const requestMsg = new ", method.input, "(request)");
|
|
121
|
+
f.print(" const result = await this.rpc.request(");
|
|
122
|
+
f.print(" this.service,");
|
|
123
|
+
f.print(" ", localName(service), "Definition.methods.", method.name, ".name,");
|
|
124
|
+
f.print(" requestMsg.toBinary(),");
|
|
125
|
+
f.print(" abortSignal || undefined,");
|
|
126
|
+
f.print(" )");
|
|
127
|
+
f.print(" return ", method.output, ".fromBinary(result)");
|
|
128
|
+
f.print(" }");
|
|
129
|
+
}
|
|
130
|
+
else if (method.methodKind === MethodKind.ServerStreaming) {
|
|
131
|
+
f.print(MessageStream, "<", method.output, "> {");
|
|
132
|
+
f.print(" const requestMsg = new ", method.input, "(request)");
|
|
133
|
+
f.print(" const result = this.rpc.serverStreamingRequest(");
|
|
134
|
+
f.print(" this.service,");
|
|
135
|
+
f.print(" ", localName(service), "Definition.methods.", method.name, ".name,");
|
|
136
|
+
f.print(" requestMsg.toBinary(),");
|
|
137
|
+
f.print(" abortSignal || undefined,");
|
|
138
|
+
f.print(" )");
|
|
139
|
+
f.print(" return ", buildDecodeMessageTransformSymbol, "(", method.output, ")(result)");
|
|
140
|
+
f.print(" }");
|
|
141
|
+
}
|
|
142
|
+
else if (method.methodKind === MethodKind.ClientStreaming) {
|
|
143
|
+
f.print("Promise<", PartialMessage, "<", method.output, ">> {");
|
|
144
|
+
f.print(" const result = await this.rpc.clientStreamingRequest(");
|
|
145
|
+
f.print(" this.service,");
|
|
146
|
+
f.print(" ", localName(service), "Definition.methods.", method.name, ".name,");
|
|
147
|
+
f.print(" ", buildEncodeMessageTransformSymbol, "(", method.input, ")(request),");
|
|
148
|
+
f.print(" abortSignal || undefined,");
|
|
149
|
+
f.print(" )");
|
|
150
|
+
f.print(" return ", method.output, ".fromBinary(result)");
|
|
151
|
+
f.print(" }");
|
|
152
|
+
}
|
|
153
|
+
else if (method.methodKind === MethodKind.BiDiStreaming) {
|
|
154
|
+
f.print(MessageStream, "<", method.output, "> {");
|
|
155
|
+
f.print(" const result = this.rpc.bidirectionalStreamingRequest(");
|
|
156
|
+
f.print(" this.service,");
|
|
157
|
+
f.print(" ", localName(service), "Definition.methods.", method.name, ".name,");
|
|
158
|
+
f.print(" ", buildEncodeMessageTransformSymbol, "(", method.input, ")(request),");
|
|
159
|
+
f.print(" abortSignal || undefined,");
|
|
160
|
+
f.print(" )");
|
|
161
|
+
f.print(" return ", buildDecodeMessageTransformSymbol, "(", method.output, ")(result)");
|
|
162
|
+
f.print(" }");
|
|
163
|
+
}
|
|
164
|
+
f.print();
|
|
165
|
+
}
|
|
166
|
+
f.print("}");
|
|
167
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from '@bufbuild/protobuf';
|
|
2
|
+
import { Message, proto3 } from '@bufbuild/protobuf';
|
|
3
|
+
/**
|
|
4
|
+
* MockMsg is the mock message body.
|
|
5
|
+
*
|
|
6
|
+
* @generated from message e2e.mock.MockMsg
|
|
7
|
+
*/
|
|
8
|
+
export declare class MockMsg extends Message<MockMsg> {
|
|
9
|
+
/**
|
|
10
|
+
* @generated from field: string body = 1;
|
|
11
|
+
*/
|
|
12
|
+
body: string;
|
|
13
|
+
constructor(data?: PartialMessage<MockMsg>);
|
|
14
|
+
static readonly runtime: typeof proto3;
|
|
15
|
+
static readonly typeName = "e2e.mock.MockMsg";
|
|
16
|
+
static readonly fields: FieldList;
|
|
17
|
+
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): MockMsg;
|
|
18
|
+
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): MockMsg;
|
|
19
|
+
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): MockMsg;
|
|
20
|
+
static equals(a: MockMsg | PlainMessage<MockMsg> | undefined, b: MockMsg | PlainMessage<MockMsg> | undefined): boolean;
|
|
21
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// @generated by protoc-gen-es v1.8.0 with parameter "target=ts,ts_nocheck=false"
|
|
2
|
+
// @generated from file github.com/aperturerobotics/starpc/e2e/mock/mock.proto (package e2e.mock, syntax proto3)
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
import { Message, proto3 } from '@bufbuild/protobuf';
|
|
5
|
+
/**
|
|
6
|
+
* MockMsg is the mock message body.
|
|
7
|
+
*
|
|
8
|
+
* @generated from message e2e.mock.MockMsg
|
|
9
|
+
*/
|
|
10
|
+
export class MockMsg extends Message {
|
|
11
|
+
constructor(data) {
|
|
12
|
+
super();
|
|
13
|
+
/**
|
|
14
|
+
* @generated from field: string body = 1;
|
|
15
|
+
*/
|
|
16
|
+
this.body = '';
|
|
17
|
+
proto3.util.initPartial(data, this);
|
|
18
|
+
}
|
|
19
|
+
static fromBinary(bytes, options) {
|
|
20
|
+
return new MockMsg().fromBinary(bytes, options);
|
|
21
|
+
}
|
|
22
|
+
static fromJson(jsonValue, options) {
|
|
23
|
+
return new MockMsg().fromJson(jsonValue, options);
|
|
24
|
+
}
|
|
25
|
+
static fromJsonString(jsonString, options) {
|
|
26
|
+
return new MockMsg().fromJsonString(jsonString, options);
|
|
27
|
+
}
|
|
28
|
+
static equals(a, b) {
|
|
29
|
+
return proto3.util.equals(MockMsg, a, b);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
MockMsg.runtime = proto3;
|
|
33
|
+
MockMsg.typeName = 'e2e.mock.MockMsg';
|
|
34
|
+
MockMsg.fields = proto3.util.newFieldList(() => [
|
|
35
|
+
{ no: 1, name: 'body', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
|
36
|
+
]);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { MockMsg } from './mock_pb.js';
|
|
2
|
+
import type { PartialMessage } from '@bufbuild/protobuf';
|
|
3
|
+
import { MethodKind } from '@bufbuild/protobuf';
|
|
4
|
+
import { ProtoRpc } from 'starpc';
|
|
5
|
+
/**
|
|
6
|
+
* Mock service mocks some RPCs for the e2e tests.
|
|
7
|
+
*
|
|
8
|
+
* @generated from service e2e.mock.Mock
|
|
9
|
+
*/
|
|
10
|
+
export declare const MockDefinition: {
|
|
11
|
+
readonly typeName: "e2e.mock.Mock";
|
|
12
|
+
readonly methods: {
|
|
13
|
+
/**
|
|
14
|
+
* MockRequest runs a mock unary request.
|
|
15
|
+
*
|
|
16
|
+
* @generated from rpc e2e.mock.Mock.MockRequest
|
|
17
|
+
*/
|
|
18
|
+
readonly MockRequest: {
|
|
19
|
+
readonly name: "MockRequest";
|
|
20
|
+
readonly I: typeof MockMsg;
|
|
21
|
+
readonly O: typeof MockMsg;
|
|
22
|
+
readonly kind: MethodKind.Unary;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Mock service mocks some RPCs for the e2e tests.
|
|
28
|
+
*
|
|
29
|
+
* @generated from service e2e.mock.Mock
|
|
30
|
+
*/
|
|
31
|
+
export interface Mock {
|
|
32
|
+
/**
|
|
33
|
+
* MockRequest runs a mock unary request.
|
|
34
|
+
*
|
|
35
|
+
* @generated from rpc e2e.mock.Mock.MockRequest
|
|
36
|
+
*/
|
|
37
|
+
MockRequest(request: PartialMessage<MockMsg>, abortSignal?: AbortSignal): Promise<PartialMessage<MockMsg>>;
|
|
38
|
+
}
|
|
39
|
+
export declare const MockServiceName: "e2e.mock.Mock";
|
|
40
|
+
export declare class MockClient implements Mock {
|
|
41
|
+
private readonly rpc;
|
|
42
|
+
private readonly service;
|
|
43
|
+
constructor(rpc: ProtoRpc, opts?: {
|
|
44
|
+
service?: string;
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* MockRequest runs a mock unary request.
|
|
48
|
+
*
|
|
49
|
+
* @generated from rpc e2e.mock.Mock.MockRequest
|
|
50
|
+
*/
|
|
51
|
+
MockRequest(request: PartialMessage<MockMsg>, abortSignal?: AbortSignal): Promise<PartialMessage<MockMsg>>;
|
|
52
|
+
}
|