@trevrpc/trevrpc-js 0.1.0 → 0.1.9

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 CHANGED
@@ -1,202 +1,96 @@
1
1
  # trevrpc-js
2
2
 
3
- `trevrpc-js` is the ESM-only JavaScript runtime and protobuf.js generator for TrevRPC.
3
+ TrevRPC is an RPC framework like gRPC, but uses QUIC (and HTTP/3 / WebTransport) instead of HTTP/2. Define services in protobuf, generate typed clients and servers, and run them over QUIC.
4
4
 
5
- ## Generated files
5
+ Full documentation: https://trev.zip/llc/TrevRPC/wiki
6
6
 
7
- For every protobuf file containing services, `protoc-gen-trevrpc-js` emits an ordinary browser-safe client module and a separate Node server module:
7
+ ## Protobuf
8
8
 
9
- ```text
10
- greeter.trevrpc.js
11
- greeter.trevrpc.d.ts
12
- greeter.node.trevrpc.js
13
- greeter.node.trevrpc.d.ts
14
- ```
15
-
16
- The ordinary module contains the protobuf root, service descriptors, typed clients, and client factories. The Node companion contains typed handler interfaces and registration helpers backed by `@trevrpc/trevrpc-js/node/generated`.
17
-
18
- ```sh
19
- protoc \
20
- --plugin=protoc-gen-trevrpc-js=./node_modules/.bin/protoc-gen-trevrpc-js \
21
- --trevrpc-js_out=. \
22
- greeter.proto
23
- ```
9
+ ```proto
10
+ syntax = "proto3";
24
11
 
25
- Generator options are `runtime_import`, `runtime_type_import`, `node_runtime_import`, `node_runtime_type_import`, and `file_suffix`. Runtime type imports default to their matching runtime import for bare and relative specifiers. URL specifiers such as `file:` require an explicit type import because TypeScript NodeNext does not resolve them in declarations. A Node import is never inferred by appending `/node` to another specifier.
12
+ package example.greeter;
26
13
 
27
- ## Browser clients
28
-
29
- Browser declarations accept only `BrowserChannelOptions`.
30
-
31
- ```js
32
- import { connect } from "@trevrpc/trevrpc-js";
33
- import { GreeterClient } from "./greeter.trevrpc.js";
34
-
35
- const channel = await connect("https://localhost:50051/trevrpc", {
36
- timeoutMs: 10_000,
37
- congestionControl: "low-latency",
38
- serverCertificateHashes: [{ algorithm: "sha-256", value: certificateHash }],
39
- });
40
- try {
41
- const client = new GreeterClient(channel, { timeoutMs: 5_000 });
42
- const reply = await client.sayHello({ name: "TrevRPC" });
43
- console.log(reply.message);
44
- } finally {
45
- channel.close({ closeCode: 0, reason: "client shutdown" });
14
+ service Greeter {
15
+ rpc SayHello(HelloRequest) returns (HelloReply);
16
+ rpc LotsOfReplies(HelloRequest) returns (stream HelloReply);
17
+ rpc LotsOfGreetings(stream HelloRequest) returns (HelloReply);
18
+ rpc BidiHello(stream HelloRequest) returns (stream HelloReply);
46
19
  }
47
- ```
48
20
 
49
- Native TLS bypass, certificate validation, MsQuic buffering, and native stream options are intentionally unavailable under browser or Bundler resolution.
21
+ message HelloRequest { string name = 1; }
22
+ message HelloReply { string message = 1; }
23
+ ```
50
24
 
51
- ## Node clients
25
+ Generate with `protoc-gen-trevrpc-js` (`--trevrpc-js_out`).
52
26
 
53
- Under Node conditions, the root package uses the native channel. The explicit `@trevrpc/trevrpc-js/node` subpath also exports `Channel`, `NodeServer`, and `NodeServerCall`.
27
+ ## Client
54
28
 
55
29
  ```js
56
30
  import { connect } from "@trevrpc/trevrpc-js";
57
31
  import { GreeterClient } from "./greeter.trevrpc.js";
58
32
 
59
- const channel = await connect("https://localhost:50051", {
60
- timeoutMs: 10_000,
61
- caCertFile: "localhost-cert.pem",
62
- });
63
- try {
64
- console.log(channel.endpoint); // frozen { host, port }
65
- console.log(channel.options); // frozen effective NodeChannelOptions
66
- const client = new GreeterClient(channel, { timeoutMs: 5_000 });
67
- console.log((await client.sayHello({ name: "TrevRPC" })).message);
68
- } finally {
69
- channel.close();
70
- }
71
- ```
72
-
73
- URL and `{ host, port, ...options }` forms normalize to the same public state. Channels reconnect for future calls after native transport loss, but never replay or resume an operation that already failed.
74
-
75
- ## Streaming clients
76
-
77
- Server-streaming methods resolve to `ResponseAsyncIterable<T>`:
33
+ const channel = await connect("https://127.0.0.1:50051/trevrpc");
34
+ const client = new GreeterClient(channel);
78
35
 
79
- ```js
80
- const replies = await client.lotsOfReplies({ name: "TrevRPC" });
81
- try {
82
- for await (const reply of replies) {
83
- console.log(reply.message);
84
- }
85
- const terminal = await replies.status;
86
- console.log(terminal.code, terminal.message, terminal.metadata);
87
- } finally {
88
- await replies.close();
89
- }
90
- ```
36
+ // Unary
37
+ const reply = await client.sayHello({ name: "TrevRPC" });
91
38
 
92
- Full clean consumption resolves `status`. A non-OK terminal status rejects iteration and `status` with the same `TrevRpcError`. `close()`, iterator `return()`, and breaking a `for await` loop cancel the stream and reject `status` with `Code.Cancelled`. Consuming a valid terminal frame claims terminal precedence and cancels the absolute deadline, but `status` settles only after trailing EOF is validated; merely buffering a status frame is not completion.
39
+ // Server streaming
40
+ const stream = await client.lotsOfReplies({ name: "TrevRPC" });
41
+ for await (const r of stream) console.log(r.message);
93
42
 
94
- The status/error text distinction is deliberate:
43
+ // Client streaming
44
+ const cs = await client.lotsOfGreetings();
45
+ await cs.send({ name: "Alice" });
46
+ await cs.send({ name: "Bob" });
47
+ const summary = await cs.closeAndRecv();
95
48
 
96
- - `StreamStatus.message` is the unmodified peer terminal message.
97
- - `TrevRpcError.statusMessage` is the unmodified peer error message.
98
- - `TrevRpcError.message` is formatted JavaScript text such as `"Unavailable: down"`.
49
+ // Bidirectional streaming
50
+ const bidi = await client.bidiHello();
51
+ await bidi.send({ name: "Alice" });
52
+ console.log(await bidi.recv());
53
+ await bidi.closeSend();
54
+ for await (const r of bidi) console.log(r.message);
99
55
 
100
- Unary and client-streaming terminal metadata is available through `sayHelloWithResponse()` and `closeAndRecvWithResponse()`.
101
-
102
- Client streaming:
103
-
104
- ```js
105
- const call = await client.lotsOfGreetings();
106
- await call.send({ name: "Alice" });
107
- await call.send({ name: "Bob" });
108
- const { message, metadata } = await call.closeAndRecvWithResponse();
56
+ channel.close();
109
57
  ```
110
58
 
111
- Bidirectional streaming:
59
+ Node uses the same API via `@trevrpc/trevrpc-js/node` (native MsQuic).
112
60
 
113
- ```js
114
- const call = await client.bidiHello();
115
- try {
116
- await call.send({ name: "Alice" });
117
- console.log(await call.recv());
118
- await call.closeSend();
119
- while ((await call.recv()) != null) {}
120
- console.log(await call.status);
121
- } finally {
122
- await call.close();
123
- }
124
- ```
125
-
126
- `timeoutMs` is one absolute RPC deadline that begins before transport setup and covers upload, send, receive, and cleanup. The same `DeadlineExceeded` object wins signal and rejection settlement. `streamIdleTimeoutMs` remains an independent per-read inactivity bound.
127
-
128
- ## Typed Node servers
129
-
130
- Import the generated registration helper from the Node companion. Direct protobuf responses are never confused with metadata envelopes, even when they have `message` or `messages` properties.
61
+ ## Server (Node)
131
62
 
132
63
  ```js
133
- import { Code, createStreamingResponse, createUnaryResponse } from "@trevrpc/trevrpc-js";
134
64
  import { NodeServer } from "@trevrpc/trevrpc-js/node";
135
65
  import { registerGreeterServer } from "./greeter.node.trevrpc.js";
66
+ import { createUnaryResponse, createStreamingResponse } from "@trevrpc/trevrpc-js";
136
67
 
137
68
  const server = await NodeServer.listen({
138
69
  host: "127.0.0.1",
139
70
  port: 50051,
140
- certFile: "localhost-cert.pem",
141
- keyFile: "localhost-key.pem",
71
+ certFile: "cert.pem",
72
+ keyFile: "key.pem",
142
73
  });
143
74
 
144
75
  registerGreeterServer(server, {
145
- sayHello(request, call) {
146
- console.log(call.deadline, call.signal.aborted);
147
- return createUnaryResponse(
148
- { message: `Hello, ${request.name || "world"}` },
149
- { trailer: "unary" },
150
- );
76
+ sayHello(req) {
77
+ return createUnaryResponse({ message: `hello, ${req.name}` });
151
78
  },
152
-
153
- async lotsOfGreetings(requests) {
154
- const names = [];
155
- for await (const request of requests) names.push(request.name);
156
- return createUnaryResponse({ message: names.join(", ") }, { trailer: "client-stream" });
79
+ lotsOfReplies(req) {
80
+ return createStreamingResponse([
81
+ { message: `hello, ${req.name}` },
82
+ { message: `goodbye, ${req.name}` },
83
+ ]);
157
84
  },
158
-
159
- lotsOfReplies(request) {
160
- return createStreamingResponse([{ message: request.name }], {
161
- code: Code.Ok,
162
- message: "complete",
163
- metadata: { trailer: "server-stream" },
164
- });
85
+ async lotsOfGreetings(reqs) {
86
+ const names = [];
87
+ for await (const r of reqs) names.push(r.name);
88
+ return createUnaryResponse({ message: names.join(", ") });
165
89
  },
166
-
167
- async *bidiHello(requests) {
168
- for await (const request of requests) yield { message: request.name };
90
+ async *bidiHello(reqs) {
91
+ for await (const r of reqs) yield { message: `hello, ${r.name}` };
169
92
  },
170
93
  });
171
94
 
172
95
  await server.serve();
173
96
  ```
174
-
175
- Client-streaming completion uses streaming wire semantics: exactly one response message followed by exactly one terminal status; it never uses unary `respond()`.
176
-
177
- `NodeServerCall.signal` covers effective deadlines, server shutdown, local close, and cancellation observed by native I/O. The current native bridge cannot promptly report remote peer cancellation while a handler is idle and performs no call I/O; cancellation becomes observable when the handler next enters native call I/O.
178
-
179
- ## Native package support
180
-
181
- The core tarball is platform-neutral. Native code is supplied by the exact optional package `@trevrpc/trevrpc-js-native-linux-x64-gnu@0.1.0`.
182
-
183
- Initial support is Linux x86-64, glibc 2.42 or newer, and Node 24. Browser usage still installs and runs on Darwin, ARM, and musl. Requesting a native Node channel on an unsupported or incomplete installation throws `TrevRpcError(Code.Unavailable)` with the detected target, supported targets, expected optional package, whether loading was missing or failed, and the original loader error as `cause`.
184
-
185
- All addon errors crossing public Node transport and server boundaries become `TrevRpcError` unless already normalized. `nativeCode` and `cause` preserve native provenance.
186
-
187
- ## Package resolution
188
-
189
- Conditional ESM exports are authoritative; the package has no legacy top-level `main` or `types`. Use TypeScript NodeNext resolution for Node consumers and Bundler resolution with browser conditions for browser consumers.
190
-
191
- ## Native development
192
-
193
- Installation never builds native code. In a source checkout:
194
-
195
- ```sh
196
- npm run build:native:test
197
- npm test
198
- npm run build:native
199
- npm run verify:native:production
200
- ```
201
-
202
- The development fallback is only `build/native/trevrpc_native.node` in a source checkout.
@@ -1,4 +1,4 @@
1
- #!/nix/store/zvj0hl7rhh0ccr5vkcg3ijs3xm3sgyac-nodejs-24.16.0/bin/node
1
+ #!/nix/store/hwjfj8m2kcsl7kz2xa5yf84jbfh9jssf-nodejs-24.18.1/bin/node
2
2
 
3
3
  import { runGenerator } from "../src/generator.js";
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trevrpc/trevrpc-js",
3
- "version": "0.1.0",
3
+ "version": "0.1.9",
4
4
  "description": "JavaScript WebTransport runtime and protobuf.js code generator for TrevRPC",
5
5
  "homepage": "https://trev.zip/llc/TrevRPC",
6
6
  "bugs": {
@@ -54,8 +54,7 @@
54
54
  }
55
55
  },
56
56
  "publishConfig": {
57
- "access": "public",
58
- "provenance": true
57
+ "access": "public"
59
58
  },
60
59
  "scripts": {
61
60
  "build:native": "TREVRPC_NODE_TEST_HOOKS=OFF npm run build:native:cmake",
@@ -80,7 +79,7 @@
80
79
  "typescript": "^7.0.2"
81
80
  },
82
81
  "optionalDependencies": {
83
- "@trevrpc/trevrpc-js-native-linux-x64-gnu": "0.1.0"
82
+ "@trevrpc/trevrpc-js-native-linux-x64-gnu": "0.1.9"
84
83
  },
85
84
  "engines": {
86
85
  "node": ">=24 <25"
@@ -6,6 +6,13 @@ import { fileURLToPath } from "node:url";
6
6
 
7
7
  const require = createRequire(import.meta.url);
8
8
  const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
9
+ const packageVersion = (() => {
10
+ try {
11
+ return require(join(packageRoot, "package.json")).version ?? "unknown";
12
+ } catch {
13
+ return "unknown";
14
+ }
15
+ })();
9
16
  const SupportedTarget = "linux/x64/glibc";
10
17
  const LinuxX64GnuPackage = "@trevrpc/trevrpc-js-native-linux-x64-gnu";
11
18
 
@@ -45,7 +52,7 @@ export function loadNativeAddon() {
45
52
  : "the source-checkout fallback failed to load";
46
53
  throw new Error(
47
54
  `TrevRPC native addon is unavailable for detected target ${detected}. ` +
48
- `Supported targets: ${SupportedTarget}. Expected optional package: ${expected}@0.1.0; ` +
55
+ `Supported targets: ${SupportedTarget}. Expected optional package: ${expected}@${packageVersion}; ` +
49
56
  `package state: ${packageState}; ${fallbackState}. ` +
50
57
  "Install the matching optional package or build build/native/trevrpc_native.node explicitly in a source checkout; npm installation never starts a source build.",
51
58
  { cause: fallbackError ?? packageError },