@trevrpc/trevrpc-js 0.2.2 → 1.0.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/README.md +89 -47
- package/bin/protoc-gen-trevrpc-js.js +1 -1
- package/package.json +11 -41
- package/src/bytes.js +10 -0
- package/src/call.js +287 -0
- package/src/channel.js +131 -296
- package/src/client.js +203 -1292
- package/src/framing.js +125 -519
- package/src/generator.js +26 -103
- package/src/index.d.ts +79 -452
- package/src/index.js +4 -3
- package/src/status.js +24 -70
- package/src/wire.js +4 -59
- package/examples/greeter/README.md +0 -35
- package/examples/greeter/client.js +0 -172
- package/examples/greeter/greeter.node.trevrpc.d.ts +0 -53
- package/examples/greeter/greeter.node.trevrpc.js +0 -9
- package/examples/greeter/greeter.proto +0 -18
- package/examples/greeter/greeter.trevrpc.d.ts +0 -55
- package/examples/greeter/greeter.trevrpc.js +0 -103
- package/examples/greeter/index.html +0 -140
- package/examples/greeter/static-server.js +0 -168
- package/src/advanced.d.ts +0 -29
- package/src/advanced.js +0 -1
- package/src/browser-channel.js +0 -49
- package/src/connect.js +0 -6
- package/src/connect.node.js +0 -6
- package/src/index.node.d.ts +0 -10
- package/src/index.node.js +0 -3
- package/src/native-loader.js +0 -118
- package/src/node-advanced.d.ts +0 -27
- package/src/node-advanced.js +0 -1
- package/src/node-generated.d.ts +0 -24
- package/src/node-generated.js +0 -126
- package/src/node-index.d.ts +0 -1
- package/src/node-index.js +0 -7
- package/src/node.d.ts +0 -298
- package/src/node.js +0 -1456
- package/src/runtime.js +0 -66
- package/src/server-response.js +0 -49
- package/src/timer.js +0 -29
- package/src/webtransport.js +0 -639
package/src/status.js
CHANGED
|
@@ -18,82 +18,38 @@ export const Code = Object.freeze({
|
|
|
18
18
|
Unauthenticated: 16,
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
"Ok",
|
|
23
|
-
"Cancelled",
|
|
24
|
-
"Unknown",
|
|
25
|
-
"InvalidArgument",
|
|
26
|
-
"DeadlineExceeded",
|
|
27
|
-
"NotFound",
|
|
28
|
-
"AlreadyExists",
|
|
29
|
-
"PermissionDenied",
|
|
30
|
-
"ResourceExhausted",
|
|
31
|
-
"FailedPrecondition",
|
|
32
|
-
"Aborted",
|
|
33
|
-
"OutOfRange",
|
|
34
|
-
"Unimplemented",
|
|
35
|
-
"Internal",
|
|
36
|
-
"Unavailable",
|
|
37
|
-
"DataLoss",
|
|
38
|
-
"Unauthenticated",
|
|
39
|
-
]);
|
|
21
|
+
const CodeNames = Object.freeze(Object.keys(Code));
|
|
40
22
|
|
|
41
23
|
/** Error carrying a TrevRPC status code, message, and metadata. */
|
|
42
24
|
export class TrevRpcError extends Error {
|
|
43
25
|
/** Creates a TrevRPC status error. */
|
|
44
26
|
constructor(code, message = "", metadata = {}, options = {}) {
|
|
45
27
|
const normalizedCode = codeFromNumber(code);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
28
|
+
const name = codeName(normalizedCode);
|
|
29
|
+
super(
|
|
30
|
+
message === "" ? name : `${name}: ${message}`,
|
|
31
|
+
options.cause === undefined ? undefined : { cause: options.cause },
|
|
32
|
+
);
|
|
49
33
|
this.name = "TrevRpcError";
|
|
50
34
|
this.code = normalizedCode;
|
|
51
35
|
this.statusMessage = message;
|
|
52
36
|
this.metadata = metadata;
|
|
53
|
-
if (Number.isInteger(options.nativeCode)) {
|
|
54
|
-
this.nativeCode = options.nativeCode;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** Resource-exhausted status reported when a frame exceeds the configured size limit. */
|
|
60
|
-
export class FrameTooLargeError extends TrevRpcError {
|
|
61
|
-
/** Creates a frame size error. */
|
|
62
|
-
constructor(length, max) {
|
|
63
|
-
super(Code.ResourceExhausted, `frame length ${length} exceeds maximum ${max}`);
|
|
64
|
-
this.name = "FrameTooLargeError";
|
|
65
|
-
this.length = length;
|
|
66
|
-
this.max = max;
|
|
67
37
|
}
|
|
68
38
|
}
|
|
69
39
|
|
|
70
40
|
/** Converts a number into a known status code, defaulting unknown values to Unknown. */
|
|
71
41
|
export function codeFromNumber(code) {
|
|
72
|
-
return Number.isInteger(code) && code >= 0 && code <
|
|
42
|
+
return Number.isInteger(code) && code >= 0 && code < CodeNames.length ? code : Code.Unknown;
|
|
73
43
|
}
|
|
74
44
|
|
|
75
45
|
/** Returns the canonical status code name. */
|
|
76
46
|
export function codeName(code) {
|
|
77
|
-
return
|
|
47
|
+
return CodeNames[codeFromNumber(code)];
|
|
78
48
|
}
|
|
79
49
|
|
|
80
50
|
/** Creates a TrevRPC status error. */
|
|
81
|
-
export function statusError(code, message = "", metadata = {}) {
|
|
82
|
-
return new TrevRpcError(code, message, metadata);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** Builds a status error from an RPC response. */
|
|
86
|
-
export function statusFromResponse(response) {
|
|
87
|
-
if (response == null) {
|
|
88
|
-
return statusError(Code.Internal, "missing RPC response");
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return statusError(response.status ?? Code.Ok, response.message ?? "", response.metadata ?? {});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Reports whether a status-like value is OK. */
|
|
95
|
-
export function isOkStatus(status) {
|
|
96
|
-
return status != null && codeFromNumber(status.code) === Code.Ok;
|
|
51
|
+
export function statusError(code, message = "", metadata = {}, cause = undefined) {
|
|
52
|
+
return new TrevRpcError(code, message, metadata, { cause });
|
|
97
53
|
}
|
|
98
54
|
|
|
99
55
|
/** Creates an internal error status. */
|
|
@@ -102,8 +58,13 @@ export function internal(message) {
|
|
|
102
58
|
}
|
|
103
59
|
|
|
104
60
|
/** Creates an invalid-argument status. */
|
|
105
|
-
export function invalidArgument(message) {
|
|
106
|
-
return statusError(Code.InvalidArgument, message);
|
|
61
|
+
export function invalidArgument(message, cause) {
|
|
62
|
+
return statusError(Code.InvalidArgument, message, {}, cause);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Creates a failed-precondition status. */
|
|
66
|
+
export function failedPrecondition(message) {
|
|
67
|
+
return statusError(Code.FailedPrecondition, message);
|
|
107
68
|
}
|
|
108
69
|
|
|
109
70
|
/** Creates a deadline-exceeded status. */
|
|
@@ -112,8 +73,8 @@ export function deadlineExceeded(message) {
|
|
|
112
73
|
}
|
|
113
74
|
|
|
114
75
|
/** Creates an unavailable status. */
|
|
115
|
-
export function unavailable(message) {
|
|
116
|
-
return statusError(Code.Unavailable, message);
|
|
76
|
+
export function unavailable(message, cause) {
|
|
77
|
+
return statusError(Code.Unavailable, message, {}, cause);
|
|
117
78
|
}
|
|
118
79
|
|
|
119
80
|
/** Creates a resource-exhausted status. */
|
|
@@ -122,24 +83,17 @@ export function resourceExhausted(message) {
|
|
|
122
83
|
}
|
|
123
84
|
|
|
124
85
|
/** Creates a cancelled status. */
|
|
125
|
-
export function cancelled(message) {
|
|
126
|
-
return statusError(Code.Cancelled, message);
|
|
86
|
+
export function cancelled(message, cause) {
|
|
87
|
+
return statusError(Code.Cancelled, message, {}, cause);
|
|
127
88
|
}
|
|
128
89
|
|
|
129
|
-
/** Converts a transport
|
|
90
|
+
/** Converts a transport failure into a status error; status errors pass through. */
|
|
130
91
|
export function statusFromTransportError(error) {
|
|
131
92
|
if (error instanceof TrevRpcError) {
|
|
132
93
|
return error;
|
|
133
94
|
}
|
|
134
|
-
|
|
135
95
|
if (error?.name === "AbortError") {
|
|
136
|
-
return
|
|
96
|
+
return cancelled("transport closed locally", error);
|
|
137
97
|
}
|
|
138
|
-
|
|
139
|
-
return new TrevRpcError(
|
|
140
|
-
Code.Unavailable,
|
|
141
|
-
`transport unavailable: ${error?.message ?? String(error)}`,
|
|
142
|
-
{},
|
|
143
|
-
{ cause: error },
|
|
144
|
-
);
|
|
98
|
+
return unavailable(`transport unavailable: ${error?.message ?? String(error)}`, error);
|
|
145
99
|
}
|
package/src/wire.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import protobuf from "protobufjs";
|
|
2
2
|
|
|
3
|
+
import { byteView } from "./bytes.js";
|
|
4
|
+
|
|
3
5
|
export { protobuf };
|
|
4
6
|
|
|
5
7
|
export const WireVersion = 1;
|
|
@@ -16,7 +18,7 @@ export const RpcStreamFrameKind = Object.freeze({
|
|
|
16
18
|
Status: 1,
|
|
17
19
|
});
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
const wireRoot = protobuf.Root.fromJSON({
|
|
20
22
|
nested: {
|
|
21
23
|
trevrpc: {
|
|
22
24
|
nested: {
|
|
@@ -76,63 +78,16 @@ const MaxUint32 = 0xffffffffn;
|
|
|
76
78
|
const MaxUint64 = 0xffffffffffffffffn;
|
|
77
79
|
const fatalUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
78
80
|
|
|
79
|
-
/** Internal wire-validation failure used by production codec paths. */
|
|
80
|
-
export class WireValidationError extends Error {
|
|
81
|
-
constructor(reason, message) {
|
|
82
|
-
super(message);
|
|
83
|
-
this.name = "WireValidationError";
|
|
84
|
-
this.reason = reason;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
81
|
/** Checks protobuf tags and known-field wire types before protobuf.js decoding. */
|
|
89
82
|
export function preflightWireMessage(messageType, body) {
|
|
90
83
|
scanMessage(messageType, byteView(body), 0);
|
|
91
84
|
}
|
|
92
85
|
|
|
93
|
-
/** Validates TrevRPC protocol enums and versions after protobuf decoding. */
|
|
94
|
-
export function validateWireMessage(messageType, message) {
|
|
95
|
-
if (messageType === RpcRequest) {
|
|
96
|
-
if (message.version !== WireVersion) {
|
|
97
|
-
throw new WireValidationError(
|
|
98
|
-
"unsupported_wire_version",
|
|
99
|
-
`unsupported wire version ${message.version}`,
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
if (!Object.values(RpcKind).includes(message.kind)) {
|
|
103
|
-
throw new WireValidationError("unsupported_rpc_kind", `unsupported RPC kind ${message.kind}`);
|
|
104
|
-
}
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (
|
|
109
|
-
messageType === RpcStreamFrame &&
|
|
110
|
-
message.kind !== RpcStreamFrameKind.Message &&
|
|
111
|
-
message.kind !== RpcStreamFrameKind.Status
|
|
112
|
-
) {
|
|
113
|
-
throw new WireValidationError(
|
|
114
|
-
"unsupported_frame_kind",
|
|
115
|
-
`unsupported stream frame kind ${message.kind}`,
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
86
|
/** Creates a protobuf root from a JSON namespace definition. */
|
|
121
87
|
export function createRoot(json) {
|
|
122
88
|
return protobuf.Root.fromJSON(json);
|
|
123
89
|
}
|
|
124
90
|
|
|
125
|
-
/** Creates a stream message frame carrying a protobuf body. */
|
|
126
|
-
export function messageFrame(body) {
|
|
127
|
-
return {
|
|
128
|
-
kind: RpcStreamFrameKind.Message,
|
|
129
|
-
status: 0,
|
|
130
|
-
message: "",
|
|
131
|
-
body,
|
|
132
|
-
metadata: {},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
91
|
function scanMessage(messageType, bytes, depth) {
|
|
137
92
|
if (depth > 64) {
|
|
138
93
|
throw malformedWire("protobuf message nesting exceeded limit");
|
|
@@ -389,15 +344,5 @@ function validateUtf8(bytes, name) {
|
|
|
389
344
|
}
|
|
390
345
|
|
|
391
346
|
function malformedWire(message) {
|
|
392
|
-
return new
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function byteView(value) {
|
|
396
|
-
if (value instanceof Uint8Array) {
|
|
397
|
-
return value;
|
|
398
|
-
}
|
|
399
|
-
if (ArrayBuffer.isView(value)) {
|
|
400
|
-
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
401
|
-
}
|
|
402
|
-
return new Uint8Array(value ?? 0);
|
|
347
|
+
return new Error(message);
|
|
403
348
|
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Greeter example
|
|
2
|
-
|
|
3
|
-
This directory contains the generated Milestone 6 split:
|
|
4
|
-
|
|
5
|
-
- `greeter.trevrpc.js` and `.d.ts`: protobuf root, descriptors, typed clients, and factories; browser-safe.
|
|
6
|
-
- `greeter.node.trevrpc.js` and `.d.ts`: typed Node handler interfaces and `registerGreeterServer`.
|
|
7
|
-
|
|
8
|
-
Browser code must import only `greeter.trevrpc.js`. Node servers import registration from `greeter.node.trevrpc.js` and use `createUnaryResponse` or `createStreamingResponse` when returning metadata or a custom terminal status. A direct protobuf object such as `{ message: "hello" }` remains a protobuf response.
|
|
9
|
-
|
|
10
|
-
## Run the browser page
|
|
11
|
-
|
|
12
|
-
From `trevrpc-js`:
|
|
13
|
-
|
|
14
|
-
```sh
|
|
15
|
-
npm run example:greeter
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Open `http://127.0.0.1:8080/examples/greeter/` and use a WebTransport greeter endpoint:
|
|
19
|
-
|
|
20
|
-
```text
|
|
21
|
-
https://127.0.0.1:50051/trevrpc # Go default
|
|
22
|
-
https://127.0.0.1:5000/trevrpc # Rust default
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
The path selects the WebTransport session; TrevRPC routing remains inside the request frame. The example policies allow origin `http://127.0.0.1:8080` and use bearer token `trevrpc-example-token`.
|
|
26
|
-
|
|
27
|
-
Both example servers write their development certificate to `~/.config/trevrpc/trevrpc-example-cert.pem`. Override it with `TREVRPC_EXAMPLE_CERT`. The static server computes the SHA-256 DER hash and the browser client passes it through `serverCertificateHashes`.
|
|
28
|
-
|
|
29
|
-
For a temporary self-signed certificate, calculate the hash with:
|
|
30
|
-
|
|
31
|
-
```sh
|
|
32
|
-
openssl x509 -in server.pem -outform der | openssl dgst -sha256 -binary | openssl base64
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
The client fully consumes server streams, then reads terminal metadata from `stream.status`. It calls `close()` when abandoning streams. Client `timeoutMs` is absolute across setup, upload, and receive, while `streamIdleTimeoutMs` is a separate inactivity bound.
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { TrevRpcError, connect } from "../../src/index.js";
|
|
2
|
-
import { GreeterClient } from "./greeter.trevrpc.js";
|
|
3
|
-
|
|
4
|
-
const form = document.querySelector("#client-form");
|
|
5
|
-
const output = document.querySelector("#output");
|
|
6
|
-
const submit = document.querySelector("#submit");
|
|
7
|
-
|
|
8
|
-
void loadExampleDefaults();
|
|
9
|
-
|
|
10
|
-
form.addEventListener("submit", (event) => {
|
|
11
|
-
event.preventDefault();
|
|
12
|
-
void runFromForm(new FormData(form));
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
for (const preset of document.querySelectorAll("[data-url]")) {
|
|
16
|
-
preset.addEventListener("click", () => {
|
|
17
|
-
form.elements.url.value = preset.dataset.url;
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function runFromForm(data) {
|
|
22
|
-
output.textContent = "";
|
|
23
|
-
submit.disabled = true;
|
|
24
|
-
|
|
25
|
-
const url = String(data.get("url") ?? "").trim();
|
|
26
|
-
const name = String(data.get("name") ?? "TrevRPC").trim() || "TrevRPC";
|
|
27
|
-
const token = String(data.get("token") ?? "").trim();
|
|
28
|
-
const certificateHash = String(data.get("certificate-hash") ?? "").trim();
|
|
29
|
-
|
|
30
|
-
let channel;
|
|
31
|
-
try {
|
|
32
|
-
log(`connecting to ${url}`);
|
|
33
|
-
channel = await connect(url, {
|
|
34
|
-
...browserConnectOptions(certificateHash),
|
|
35
|
-
timeoutMs: 10_000,
|
|
36
|
-
});
|
|
37
|
-
const client = new GreeterClient(channel, {
|
|
38
|
-
timeoutMs: 5_000,
|
|
39
|
-
metadata: token === "" ? {} : { authorization: `Bearer ${token}` },
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const unary = await client.sayHello({ name });
|
|
43
|
-
log(`SayHello: ${unary.message}`);
|
|
44
|
-
|
|
45
|
-
const replies = await client.lotsOfReplies({ name });
|
|
46
|
-
for await (const reply of replies) {
|
|
47
|
-
log(`LotsOfReplies: ${reply.message}`);
|
|
48
|
-
}
|
|
49
|
-
const replyStatus = await replies.status;
|
|
50
|
-
log(
|
|
51
|
-
`LotsOfReplies status: ${replyStatus.code} ${replyStatus.message}; trailers=${Object.keys(replyStatus.metadata).join(",")}`,
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
const greetings = await client.lotsOfGreetings();
|
|
55
|
-
await greetings.send({ name: `${name} client stream 1` });
|
|
56
|
-
await greetings.send({ name: `${name} client stream 2` });
|
|
57
|
-
const summary = await greetings.closeAndRecvWithResponse();
|
|
58
|
-
log(
|
|
59
|
-
`LotsOfGreetings: ${summary.message.message}; trailers=${Object.keys(summary.metadata).join(",")}`,
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
const bidi = await client.bidiHello();
|
|
63
|
-
try {
|
|
64
|
-
for (const suffix of ["bidi 1", "bidi 2"]) {
|
|
65
|
-
await bidi.send({ name: `${name} ${suffix}` });
|
|
66
|
-
|
|
67
|
-
const reply = await bidi.recv();
|
|
68
|
-
if (reply == null) {
|
|
69
|
-
throw new Error("BidiHello response stream ended early");
|
|
70
|
-
}
|
|
71
|
-
log(`BidiHello: ${reply.message}`);
|
|
72
|
-
}
|
|
73
|
-
await bidi.closeSend();
|
|
74
|
-
|
|
75
|
-
for (;;) {
|
|
76
|
-
const reply = await bidi.recv();
|
|
77
|
-
if (reply == null) {
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
log(`BidiHello: ${reply.message}`);
|
|
81
|
-
}
|
|
82
|
-
} finally {
|
|
83
|
-
await bidi.close();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
log("complete");
|
|
87
|
-
} catch (error) {
|
|
88
|
-
logError(error);
|
|
89
|
-
} finally {
|
|
90
|
-
submit.disabled = false;
|
|
91
|
-
channel?.close({ closeCode: 0, reason: "example complete" });
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function browserConnectOptions(certificateHash) {
|
|
96
|
-
if (certificateHash === "") {
|
|
97
|
-
return {};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
serverCertificateHashes: [
|
|
102
|
-
{
|
|
103
|
-
algorithm: "sha-256",
|
|
104
|
-
value: parseSha256Hash(certificateHash),
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function loadExampleDefaults() {
|
|
111
|
-
try {
|
|
112
|
-
const response = await fetch("./certificate-hash.json", { cache: "no-store" });
|
|
113
|
-
if (!response.ok) {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const config = await response.json();
|
|
118
|
-
if (typeof config.bearerToken === "string" && form.elements.token.value === "") {
|
|
119
|
-
form.elements.token.value = config.bearerToken;
|
|
120
|
-
}
|
|
121
|
-
if (config.exists && typeof config.sha256Base64 === "string") {
|
|
122
|
-
form.elements["certificate-hash"].value = config.sha256Base64;
|
|
123
|
-
log(`loaded certificate hash from ${config.path}`);
|
|
124
|
-
} else if (typeof config.path === "string") {
|
|
125
|
-
log(`certificate not found at ${config.path}; start a Go or Rust example server first`);
|
|
126
|
-
}
|
|
127
|
-
} catch (error) {
|
|
128
|
-
log(`could not load local certificate hash: ${error?.message ?? String(error)}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function parseSha256Hash(value) {
|
|
133
|
-
const normalized = value
|
|
134
|
-
.trim()
|
|
135
|
-
.replace(/^sha-?256[=:]/i, "")
|
|
136
|
-
.trim();
|
|
137
|
-
const hex = normalized.replace(/[:\s]/g, "");
|
|
138
|
-
|
|
139
|
-
if (/^[0-9a-fA-F]{64}$/.test(hex)) {
|
|
140
|
-
const bytes = new Uint8Array(32);
|
|
141
|
-
for (let index = 0; index < bytes.length; index += 1) {
|
|
142
|
-
bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
|
|
143
|
-
}
|
|
144
|
-
return bytes;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const base64 = normalized.replace(/-/g, "+").replace(/_/g, "/");
|
|
148
|
-
const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), "=");
|
|
149
|
-
const binary = atob(padded);
|
|
150
|
-
if (binary.length !== 32) {
|
|
151
|
-
throw new Error("certificate hash must decode to 32 bytes of SHA-256 data");
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const bytes = new Uint8Array(binary.length);
|
|
155
|
-
for (let index = 0; index < binary.length; index += 1) {
|
|
156
|
-
bytes[index] = binary.charCodeAt(index);
|
|
157
|
-
}
|
|
158
|
-
return bytes;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function log(message) {
|
|
162
|
-
output.textContent += `${message}\n`;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function logError(error) {
|
|
166
|
-
if (error instanceof TrevRpcError) {
|
|
167
|
-
log(`RPC error: ${error.code}: ${error.statusMessage || error.message}`);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
log(`error: ${error?.message ?? String(error)}`);
|
|
172
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// Code generated by protoc-gen-trevrpc-js. DO NOT EDIT.
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
NodeServer,
|
|
5
|
-
NodeServerCall,
|
|
6
|
-
StreamingServerResponse,
|
|
7
|
-
UnaryServerResponse,
|
|
8
|
-
} from "../../src/node-generated.js";
|
|
9
|
-
import type { HelloRequest, HelloReply } from "./greeter.trevrpc.js";
|
|
10
|
-
|
|
11
|
-
/** Typed Node handlers for the Greeter service. */
|
|
12
|
-
export interface GreeterHandlers {
|
|
13
|
-
sayHello?(
|
|
14
|
-
request: HelloRequest,
|
|
15
|
-
call: NodeServerCall,
|
|
16
|
-
):
|
|
17
|
-
| HelloReply
|
|
18
|
-
| UnaryServerResponse<HelloReply>
|
|
19
|
-
| Promise<HelloReply | UnaryServerResponse<HelloReply>>;
|
|
20
|
-
lotsOfReplies?(
|
|
21
|
-
request: HelloRequest,
|
|
22
|
-
call: NodeServerCall,
|
|
23
|
-
):
|
|
24
|
-
| Iterable<HelloReply>
|
|
25
|
-
| AsyncIterable<HelloReply>
|
|
26
|
-
| StreamingServerResponse<HelloReply>
|
|
27
|
-
| Promise<
|
|
28
|
-
Iterable<HelloReply> | AsyncIterable<HelloReply> | StreamingServerResponse<HelloReply>
|
|
29
|
-
>;
|
|
30
|
-
lotsOfGreetings?(
|
|
31
|
-
requests: AsyncIterable<HelloRequest>,
|
|
32
|
-
call: NodeServerCall,
|
|
33
|
-
):
|
|
34
|
-
| HelloReply
|
|
35
|
-
| UnaryServerResponse<HelloReply>
|
|
36
|
-
| Promise<HelloReply | UnaryServerResponse<HelloReply>>;
|
|
37
|
-
bidiHello?(
|
|
38
|
-
requests: AsyncIterable<HelloRequest>,
|
|
39
|
-
call: NodeServerCall,
|
|
40
|
-
):
|
|
41
|
-
| Iterable<HelloReply>
|
|
42
|
-
| AsyncIterable<HelloReply>
|
|
43
|
-
| StreamingServerResponse<HelloReply>
|
|
44
|
-
| Promise<
|
|
45
|
-
Iterable<HelloReply> | AsyncIterable<HelloReply> | StreamingServerResponse<HelloReply>
|
|
46
|
-
>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Registers typed Node handlers for the Greeter service. */
|
|
50
|
-
export declare function registerGreeterServer(
|
|
51
|
-
server: NodeServer,
|
|
52
|
-
handlers: GreeterHandlers,
|
|
53
|
-
): NodeServer;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// Code generated by protoc-gen-trevrpc-js. DO NOT EDIT.
|
|
2
|
-
|
|
3
|
-
import { registerTypedService } from "../../src/node-generated.js";
|
|
4
|
-
import { GreeterService, root } from "./greeter.trevrpc.js";
|
|
5
|
-
|
|
6
|
-
/** Registers typed Node handlers for the Greeter service. */
|
|
7
|
-
export function registerGreeterServer(server, handlers) {
|
|
8
|
-
return registerTypedService(server, root, GreeterService, handlers);
|
|
9
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
syntax = "proto3";
|
|
2
|
-
|
|
3
|
-
package example.greeter;
|
|
4
|
-
|
|
5
|
-
service Greeter {
|
|
6
|
-
rpc SayHello(HelloRequest) returns (HelloReply);
|
|
7
|
-
rpc LotsOfReplies(HelloRequest) returns (stream HelloReply);
|
|
8
|
-
rpc LotsOfGreetings(stream HelloRequest) returns (HelloReply);
|
|
9
|
-
rpc BidiHello(stream HelloRequest) returns (stream HelloReply);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
message HelloRequest {
|
|
13
|
-
string name = 1;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
message HelloReply {
|
|
17
|
-
string message = 1;
|
|
18
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// Code generated by protoc-gen-trevrpc-js. DO NOT EDIT.
|
|
2
|
-
|
|
3
|
-
import type { Long, Root } from "protobufjs";
|
|
4
|
-
|
|
5
|
-
import type {
|
|
6
|
-
BidirectionalStreamingCall,
|
|
7
|
-
CallOptions,
|
|
8
|
-
ClientStreamingCall,
|
|
9
|
-
ResponseAsyncIterable,
|
|
10
|
-
RpcServiceDescriptor,
|
|
11
|
-
Transport,
|
|
12
|
-
UnaryResponse,
|
|
13
|
-
} from "../../src/index.js";
|
|
14
|
-
|
|
15
|
-
export declare const root: Root;
|
|
16
|
-
|
|
17
|
-
export interface HelloRequest {
|
|
18
|
-
name?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface HelloReply {
|
|
22
|
-
message?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Service descriptor for the Greeter service. */
|
|
26
|
-
export declare const GreeterService: RpcServiceDescriptor;
|
|
27
|
-
|
|
28
|
-
/** Client for the Greeter service. */
|
|
29
|
-
export declare class GreeterClient {
|
|
30
|
-
/** Creates a client for the Greeter service. */
|
|
31
|
-
constructor(transport: Transport, options?: CallOptions);
|
|
32
|
-
|
|
33
|
-
/** Calls the SayHello RPC. */
|
|
34
|
-
sayHello(request: HelloRequest, options?: CallOptions): Promise<HelloReply>;
|
|
35
|
-
/** Calls the SayHello RPC and returns response metadata. */
|
|
36
|
-
sayHelloWithResponse(
|
|
37
|
-
request: HelloRequest,
|
|
38
|
-
options?: CallOptions,
|
|
39
|
-
): Promise<UnaryResponse<HelloReply>>;
|
|
40
|
-
/** Calls the LotsOfReplies RPC. */
|
|
41
|
-
lotsOfReplies(
|
|
42
|
-
request: HelloRequest,
|
|
43
|
-
options?: CallOptions,
|
|
44
|
-
): Promise<ResponseAsyncIterable<HelloReply>>;
|
|
45
|
-
/** Calls the LotsOfGreetings RPC. */
|
|
46
|
-
lotsOfGreetings(options?: CallOptions): Promise<ClientStreamingCall<HelloRequest, HelloReply>>;
|
|
47
|
-
/** Calls the BidiHello RPC. */
|
|
48
|
-
bidiHello(options?: CallOptions): Promise<BidirectionalStreamingCall<HelloRequest, HelloReply>>;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Creates a client for the Greeter service. */
|
|
52
|
-
export declare function createGreeterClient(
|
|
53
|
-
transport: Transport,
|
|
54
|
-
options?: CallOptions,
|
|
55
|
-
): GreeterClient;
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
// Code generated by protoc-gen-trevrpc-js. DO NOT EDIT.
|
|
2
|
-
|
|
3
|
-
import { createRoot, createServiceClient } from "../../src/index.js";
|
|
4
|
-
|
|
5
|
-
export const root = createRoot({
|
|
6
|
-
nested: {
|
|
7
|
-
example: {
|
|
8
|
-
nested: {
|
|
9
|
-
greeter: {
|
|
10
|
-
nested: {
|
|
11
|
-
HelloRequest: {
|
|
12
|
-
fields: {
|
|
13
|
-
name: {
|
|
14
|
-
type: "string",
|
|
15
|
-
id: 1,
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
HelloReply: {
|
|
20
|
-
fields: {
|
|
21
|
-
message: {
|
|
22
|
-
type: "string",
|
|
23
|
-
id: 1,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
/** Service descriptor for the Greeter service. */
|
|
35
|
-
export const GreeterService = Object.freeze({
|
|
36
|
-
name: "Greeter",
|
|
37
|
-
fullName: "example.greeter.Greeter",
|
|
38
|
-
exportName: "GreeterService",
|
|
39
|
-
methods: {
|
|
40
|
-
sayHello: {
|
|
41
|
-
name: "SayHello",
|
|
42
|
-
kind: "unary",
|
|
43
|
-
inputType: "example.greeter.HelloRequest",
|
|
44
|
-
outputType: "example.greeter.HelloReply",
|
|
45
|
-
},
|
|
46
|
-
lotsOfReplies: {
|
|
47
|
-
name: "LotsOfReplies",
|
|
48
|
-
kind: "serverStreaming",
|
|
49
|
-
inputType: "example.greeter.HelloRequest",
|
|
50
|
-
outputType: "example.greeter.HelloReply",
|
|
51
|
-
},
|
|
52
|
-
lotsOfGreetings: {
|
|
53
|
-
name: "LotsOfGreetings",
|
|
54
|
-
kind: "clientStreaming",
|
|
55
|
-
inputType: "example.greeter.HelloRequest",
|
|
56
|
-
outputType: "example.greeter.HelloReply",
|
|
57
|
-
},
|
|
58
|
-
bidiHello: {
|
|
59
|
-
name: "BidiHello",
|
|
60
|
-
kind: "bidirectionalStreaming",
|
|
61
|
-
inputType: "example.greeter.HelloRequest",
|
|
62
|
-
outputType: "example.greeter.HelloReply",
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
/** Client for the Greeter service. */
|
|
68
|
-
export class GreeterClient {
|
|
69
|
-
/** Creates a client for the Greeter service. */
|
|
70
|
-
constructor(transport, options = {}) {
|
|
71
|
-
this._client = createServiceClient(transport, GreeterService, root, options);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** Calls the SayHello RPC. */
|
|
75
|
-
sayHello(request, options = {}) {
|
|
76
|
-
return this._client.sayHello(request, options);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Calls the SayHello RPC and returns response metadata. */
|
|
80
|
-
sayHelloWithResponse(request, options = {}) {
|
|
81
|
-
return this._client.sayHelloWithResponse(request, options);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/** Calls the LotsOfReplies RPC. */
|
|
85
|
-
lotsOfReplies(request, options = {}) {
|
|
86
|
-
return this._client.lotsOfReplies(request, options);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** Calls the LotsOfGreetings RPC. */
|
|
90
|
-
lotsOfGreetings(options = {}) {
|
|
91
|
-
return this._client.lotsOfGreetings(options);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Calls the BidiHello RPC. */
|
|
95
|
-
bidiHello(options = {}) {
|
|
96
|
-
return this._client.bidiHello(options);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** Creates a client for the Greeter service. */
|
|
101
|
-
export function createGreeterClient(transport, options = {}) {
|
|
102
|
-
return new GreeterClient(transport, options);
|
|
103
|
-
}
|