@trevrpc/trevrpc-js 0.2.3 → 1.1.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 +127 -46
- package/package.json +12 -45
- package/src/bytes.js +10 -0
- package/src/call.js +520 -0
- package/src/channel.js +258 -288
- package/src/client.js +543 -1254
- package/src/datagram.js +336 -0
- package/src/framing.js +151 -548
- package/src/generator.js +66 -109
- package/src/index.d.ts +235 -463
- package/src/index.js +4 -3
- package/src/qmux/frames.js +262 -0
- package/src/qmux/params.js +104 -0
- package/src/qmux/session.js +739 -0
- package/src/race.js +90 -0
- package/src/status.js +24 -70
- package/src/varint.js +73 -0
- package/src/wire.js +21 -89
- 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/generator.js
CHANGED
|
@@ -89,6 +89,18 @@ message MethodDescriptorProto {
|
|
|
89
89
|
optional string output_type = 3;
|
|
90
90
|
optional bool client_streaming = 5 [default = false];
|
|
91
91
|
optional bool server_streaming = 6 [default = false];
|
|
92
|
+
optional MethodOptions options = 4;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Only the trevrpc.method extension is modelled; protobuf.js keeps every other extension out of
|
|
96
|
+
// the decoded message. The numbers are those of proto/trevrpc/options.proto.
|
|
97
|
+
message MethodOptions {
|
|
98
|
+
optional TrevrpcMethodOptions trevrpc_method = 58247;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
message TrevrpcMethodOptions {
|
|
102
|
+
optional bool unreliable_requests = 1;
|
|
103
|
+
optional bool unreliable_responses = 2;
|
|
92
104
|
}
|
|
93
105
|
|
|
94
106
|
message FileOptions {
|
|
@@ -166,6 +178,13 @@ const FieldLabel = Object.freeze({
|
|
|
166
178
|
Repeated: 3,
|
|
167
179
|
});
|
|
168
180
|
|
|
181
|
+
/** Generic runtime types that generated declarations import only when they use them. */
|
|
182
|
+
const GeneratedTypeImports = [
|
|
183
|
+
"BidirectionalStreamingCall",
|
|
184
|
+
"ClientStreamingCall",
|
|
185
|
+
"ResponseStream",
|
|
186
|
+
];
|
|
187
|
+
|
|
169
188
|
const RESERVED_WORDS = new Set([
|
|
170
189
|
"break",
|
|
171
190
|
"case",
|
|
@@ -225,7 +244,6 @@ export function generate(request) {
|
|
|
225
244
|
}
|
|
226
245
|
|
|
227
246
|
const fileName = outputFileName(file.name, options.fileSuffix);
|
|
228
|
-
const nodeFileName = outputFileName(file.name, `.node${options.fileSuffix}`);
|
|
229
247
|
files.push({
|
|
230
248
|
name: fileName,
|
|
231
249
|
content: generateFile(file, rootJson, options),
|
|
@@ -234,14 +252,6 @@ export function generate(request) {
|
|
|
234
252
|
name: declarationFileName(fileName),
|
|
235
253
|
content: generateDeclarationFile(protoFiles, file, typeNames, options),
|
|
236
254
|
});
|
|
237
|
-
files.push({
|
|
238
|
-
name: nodeFileName,
|
|
239
|
-
content: generateNodeFile(file, fileName, options),
|
|
240
|
-
});
|
|
241
|
-
files.push({
|
|
242
|
-
name: declarationFileName(nodeFileName),
|
|
243
|
-
content: generateNodeDeclarationFile(file, fileName, typeNames, options),
|
|
244
|
-
});
|
|
245
255
|
}
|
|
246
256
|
|
|
247
257
|
return { file: files };
|
|
@@ -255,8 +265,6 @@ export function parseOptions(parameter) {
|
|
|
255
265
|
const options = {
|
|
256
266
|
runtimeImport: "@trevrpc/trevrpc-js",
|
|
257
267
|
runtimeTypeImport: null,
|
|
258
|
-
nodeRuntimeImport: "@trevrpc/trevrpc-js/node/generated",
|
|
259
|
-
nodeRuntimeTypeImport: null,
|
|
260
268
|
fileSuffix: ".trevrpc.js",
|
|
261
269
|
};
|
|
262
270
|
|
|
@@ -279,12 +287,6 @@ export function parseOptions(parameter) {
|
|
|
279
287
|
case "runtime_type_import":
|
|
280
288
|
options.runtimeTypeImport = value;
|
|
281
289
|
break;
|
|
282
|
-
case "node_runtime_import":
|
|
283
|
-
options.nodeRuntimeImport = value;
|
|
284
|
-
break;
|
|
285
|
-
case "node_runtime_type_import":
|
|
286
|
-
options.nodeRuntimeTypeImport = value;
|
|
287
|
-
break;
|
|
288
290
|
case "file_suffix":
|
|
289
291
|
options.fileSuffix = value;
|
|
290
292
|
break;
|
|
@@ -293,29 +295,15 @@ export function parseOptions(parameter) {
|
|
|
293
295
|
}
|
|
294
296
|
}
|
|
295
297
|
|
|
296
|
-
options.runtimeTypeImport
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
options.nodeRuntimeImport,
|
|
304
|
-
options.nodeRuntimeTypeImport,
|
|
305
|
-
);
|
|
306
|
-
return options;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function resolveTypeImport(optionName, runtimeImport, typeImport) {
|
|
310
|
-
if (typeImport != null) {
|
|
311
|
-
return typeImport;
|
|
312
|
-
}
|
|
313
|
-
if (/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(runtimeImport)) {
|
|
314
|
-
throw new Error(
|
|
315
|
-
`${optionName} ${JSON.stringify(runtimeImport)} requires an explicit ${optionName.replace("_import", "_type_import")}`,
|
|
316
|
-
);
|
|
298
|
+
if (options.runtimeTypeImport == null) {
|
|
299
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(options.runtimeImport)) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
`runtime_import ${JSON.stringify(options.runtimeImport)} requires an explicit runtime_type_import`,
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
options.runtimeTypeImport = options.runtimeImport;
|
|
317
305
|
}
|
|
318
|
-
return
|
|
306
|
+
return options;
|
|
319
307
|
}
|
|
320
308
|
|
|
321
309
|
/** Builds a protobuf.js JSON root from protobuf file descriptors. */
|
|
@@ -354,36 +342,19 @@ function generateDeclarationFile(protoFiles, file, typeNames, options) {
|
|
|
354
342
|
.map((service) => generateServiceDeclaration(service, typeNames))
|
|
355
343
|
.join("\n\n");
|
|
356
344
|
const sections = [messages, services].filter(Boolean).join("\n\n");
|
|
357
|
-
|
|
358
|
-
|
|
345
|
+
const protobufImports = sections.includes("string | Long") ? "Long, Root" : "Root";
|
|
346
|
+
const runtimeImports = [
|
|
347
|
+
"CallOptions",
|
|
348
|
+
"RpcServiceDescriptor",
|
|
349
|
+
"Transport",
|
|
350
|
+
...GeneratedTypeImports.filter((name) => sections.includes(`${name}<`)),
|
|
351
|
+
].sort();
|
|
352
|
+
|
|
353
|
+
return `// Code generated by protoc-gen-trevrpc-js. DO NOT EDIT.\n\nimport type { ${protobufImports} } from "protobufjs";\n\nimport type { ${runtimeImports.join(", ")} } from ${JSON.stringify(
|
|
359
354
|
options.runtimeTypeImport,
|
|
360
355
|
)};\n\nexport declare const root: Root;\n\n${sections}\n`;
|
|
361
356
|
}
|
|
362
357
|
|
|
363
|
-
function generateNodeFile(file, ordinaryFileName, options) {
|
|
364
|
-
const services = (file.service ?? []).map((service) => serviceDescriptor(file, service));
|
|
365
|
-
const serviceNames = services.map((service) => service.exportName).join(", ");
|
|
366
|
-
const registrations = services.map(generateNodeServerRegistration).join("\n");
|
|
367
|
-
return `// Code generated by protoc-gen-trevrpc-js. DO NOT EDIT.\n\nimport { registerTypedService } from ${JSON.stringify(
|
|
368
|
-
options.nodeRuntimeImport,
|
|
369
|
-
)};\nimport { ${serviceNames}, root } from ${JSON.stringify(localModuleSpecifier(ordinaryFileName))};\n\n${registrations}`;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function generateNodeDeclarationFile(file, ordinaryFileName, typeNames, options) {
|
|
373
|
-
const services = (file.service ?? []).map((service) => serviceDescriptor(file, service));
|
|
374
|
-
const messageNames = [...new Set(typeNames.values())].join(", ");
|
|
375
|
-
const messageImport =
|
|
376
|
-
messageNames === ""
|
|
377
|
-
? ""
|
|
378
|
-
: `import type { ${messageNames} } from ${JSON.stringify(localModuleSpecifier(ordinaryFileName))};\n`;
|
|
379
|
-
const declarations = services
|
|
380
|
-
.map((service) => generateNodeServiceDeclaration(service, typeNames))
|
|
381
|
-
.join("\n\n");
|
|
382
|
-
return `// Code generated by protoc-gen-trevrpc-js. DO NOT EDIT.\n\nimport type { NodeServer, NodeServerCall, StreamingServerResponse, UnaryServerResponse } from ${JSON.stringify(
|
|
383
|
-
options.nodeRuntimeTypeImport,
|
|
384
|
-
)};\n${messageImport}\n${declarations}\n`;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
358
|
function generateService(service) {
|
|
388
359
|
const className = `${pascalIdentifier(service.name)}Client`;
|
|
389
360
|
const factoryName = `create${className}`;
|
|
@@ -398,18 +369,9 @@ function generateServiceMethod(jsName, method) {
|
|
|
398
369
|
return ` /** Calls the ${method.name} RPC. */\n ${jsName}(options = {}) {\n return this._client.${jsName}(options);\n }`;
|
|
399
370
|
}
|
|
400
371
|
|
|
401
|
-
if (method.kind === "unary") {
|
|
402
|
-
return ` /** Calls the ${method.name} RPC. */\n ${jsName}(request, options = {}) {\n return this._client.${jsName}(request, options);\n }\n\n /** Calls the ${method.name} RPC and returns response metadata. */\n ${jsName}WithResponse(request, options = {}) {\n return this._client.${jsName}WithResponse(request, options);\n }`;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
372
|
return ` /** Calls the ${method.name} RPC. */\n ${jsName}(request, options = {}) {\n return this._client.${jsName}(request, options);\n }`;
|
|
406
373
|
}
|
|
407
374
|
|
|
408
|
-
function generateNodeServerRegistration(service) {
|
|
409
|
-
const registerName = `register${pascalIdentifier(service.name)}Server`;
|
|
410
|
-
return `/** Registers typed Node handlers for the ${service.name} service. */\nexport function ${registerName}(server, handlers) {\n return registerTypedService(server, root, ${service.exportName}, handlers);\n}\n`;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
375
|
function generateServiceDeclaration(service, typeNames) {
|
|
414
376
|
const className = `${pascalIdentifier(service.name)}Client`;
|
|
415
377
|
const factoryName = `create${className}`;
|
|
@@ -420,24 +382,15 @@ function generateServiceDeclaration(service, typeNames) {
|
|
|
420
382
|
return `/** Service descriptor for the ${service.name} service. */\nexport declare const ${service.exportName}: RpcServiceDescriptor;\n\n/** Client for the ${service.name} service. */\nexport declare class ${className} {\n /** Creates a client for the ${service.name} service. */\n constructor(transport: Transport, options?: CallOptions);\n\n${methods}\n}\n\n/** Creates a client for the ${service.name} service. */\nexport declare function ${factoryName}(transport: Transport, options?: CallOptions): ${className};`;
|
|
421
383
|
}
|
|
422
384
|
|
|
423
|
-
function generateNodeServiceDeclaration(service, typeNames) {
|
|
424
|
-
const handlerName = `${pascalIdentifier(service.name)}Handlers`;
|
|
425
|
-
const registerName = `register${pascalIdentifier(service.name)}Server`;
|
|
426
|
-
const handlers = Object.entries(service.methods)
|
|
427
|
-
.map(([jsName, method]) => generateHandlerDeclaration(jsName, method, typeNames))
|
|
428
|
-
.join("\n");
|
|
429
|
-
return `/** Typed Node handlers for the ${service.name} service. */\nexport interface ${handlerName} {\n${handlers}\n}\n\n/** Registers typed Node handlers for the ${service.name} service. */\nexport declare function ${registerName}(server: NodeServer, handlers: ${handlerName}): NodeServer;`;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
385
|
function generateMethodDeclaration(jsName, method, typeNames) {
|
|
433
386
|
const inputType = declarationTypeReference(method.inputType, typeNames);
|
|
434
387
|
const outputType = declarationTypeReference(method.outputType, typeNames);
|
|
435
388
|
|
|
436
389
|
switch (method.kind) {
|
|
437
390
|
case "unary":
|
|
438
|
-
return ` /** Calls the ${method.name} RPC. */\n ${jsName}(request: ${inputType}, options?: CallOptions): Promise<${outputType}
|
|
391
|
+
return ` /** Calls the ${method.name} RPC. */\n ${jsName}(request: ${inputType}, options?: CallOptions): Promise<${outputType}>;`;
|
|
439
392
|
case "serverStreaming":
|
|
440
|
-
return ` /** Calls the ${method.name} RPC. */\n ${jsName}(request: ${inputType}, options?: CallOptions): Promise<
|
|
393
|
+
return ` /** Calls the ${method.name} RPC. */\n ${jsName}(request: ${inputType}, options?: CallOptions): Promise<ResponseStream<${outputType}>>;`;
|
|
441
394
|
case "clientStreaming":
|
|
442
395
|
return ` /** Calls the ${method.name} RPC. */\n ${jsName}(options?: CallOptions): Promise<ClientStreamingCall<${inputType}, ${outputType}>>;`;
|
|
443
396
|
case "bidirectionalStreaming":
|
|
@@ -447,25 +400,6 @@ function generateMethodDeclaration(jsName, method, typeNames) {
|
|
|
447
400
|
}
|
|
448
401
|
}
|
|
449
402
|
|
|
450
|
-
function generateHandlerDeclaration(jsName, method, typeNames) {
|
|
451
|
-
const inputType = declarationTypeReference(method.inputType, typeNames);
|
|
452
|
-
const outputType = declarationTypeReference(method.outputType, typeNames);
|
|
453
|
-
const unaryResult = `${outputType} | UnaryServerResponse<${outputType}>`;
|
|
454
|
-
const streamingResult = `Iterable<${outputType}> | AsyncIterable<${outputType}> | StreamingServerResponse<${outputType}>`;
|
|
455
|
-
switch (method.kind) {
|
|
456
|
-
case "unary":
|
|
457
|
-
return ` ${jsName}?(request: ${inputType}, call: NodeServerCall): ${unaryResult} | Promise<${unaryResult}>;`;
|
|
458
|
-
case "serverStreaming":
|
|
459
|
-
return ` ${jsName}?(request: ${inputType}, call: NodeServerCall): ${streamingResult} | Promise<${streamingResult}>;`;
|
|
460
|
-
case "clientStreaming":
|
|
461
|
-
return ` ${jsName}?(requests: AsyncIterable<${inputType}>, call: NodeServerCall): ${unaryResult} | Promise<${unaryResult}>;`;
|
|
462
|
-
case "bidirectionalStreaming":
|
|
463
|
-
return ` ${jsName}?(requests: AsyncIterable<${inputType}>, call: NodeServerCall): ${streamingResult} | Promise<${streamingResult}>;`;
|
|
464
|
-
default:
|
|
465
|
-
throw new Error(`unsupported generated RPC kind ${JSON.stringify(method.kind)}`);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
403
|
function serviceDescriptor(file, service) {
|
|
470
404
|
const fullName =
|
|
471
405
|
file.package === "" || file.package == null ? service.name : `${file.package}.${service.name}`;
|
|
@@ -474,11 +408,13 @@ function serviceDescriptor(file, service) {
|
|
|
474
408
|
|
|
475
409
|
for (const method of service.method ?? []) {
|
|
476
410
|
const jsName = uniqueName(lowerCamelIdentifier(method.name), usedNames);
|
|
411
|
+
const kind = methodKind(method);
|
|
477
412
|
methods[jsName] = {
|
|
478
413
|
name: method.name,
|
|
479
|
-
kind
|
|
414
|
+
kind,
|
|
480
415
|
inputType: stripLeadingDot(method.inputType),
|
|
481
416
|
outputType: stripLeadingDot(method.outputType),
|
|
417
|
+
...unreliableDirections(`${fullName}.${method.name}`, kind, method.options?.trevrpcMethod),
|
|
482
418
|
};
|
|
483
419
|
}
|
|
484
420
|
|
|
@@ -490,6 +426,31 @@ function serviceDescriptor(file, service) {
|
|
|
490
426
|
};
|
|
491
427
|
}
|
|
492
428
|
|
|
429
|
+
/**
|
|
430
|
+
* The `(trevrpc.method)` flags of a method as descriptor fields, only for the ones that are set.
|
|
431
|
+
* A flag on a direction that does not stream is an error.
|
|
432
|
+
*/
|
|
433
|
+
function unreliableDirections(methodName, kind, options) {
|
|
434
|
+
const directions = {};
|
|
435
|
+
if (options?.unreliableRequests) {
|
|
436
|
+
if (kind !== "clientStreaming" && kind !== "bidirectionalStreaming") {
|
|
437
|
+
throw new Error(
|
|
438
|
+
`${methodName}: unreliable_requests requires a client-streaming or bidirectional method`,
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
directions.unreliableRequests = true;
|
|
442
|
+
}
|
|
443
|
+
if (options?.unreliableResponses) {
|
|
444
|
+
if (kind !== "serverStreaming" && kind !== "bidirectionalStreaming") {
|
|
445
|
+
throw new Error(
|
|
446
|
+
`${methodName}: unreliable_responses requires a server-streaming or bidirectional method`,
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
directions.unreliableResponses = true;
|
|
450
|
+
}
|
|
451
|
+
return directions;
|
|
452
|
+
}
|
|
453
|
+
|
|
493
454
|
function declarationTypeNames(files) {
|
|
494
455
|
const names = new Map();
|
|
495
456
|
const usedNames = new Set();
|
|
@@ -808,10 +769,6 @@ function outputFileName(inputName, suffix) {
|
|
|
808
769
|
return `${extensionStart === -1 ? inputName : inputName.slice(0, extensionStart)}${suffix}`;
|
|
809
770
|
}
|
|
810
771
|
|
|
811
|
-
function localModuleSpecifier(fileName) {
|
|
812
|
-
return `./${fileName.slice(fileName.lastIndexOf("/") + 1)}`;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
772
|
function declarationFileName(outputName) {
|
|
816
773
|
if (outputName.endsWith(".js")) {
|
|
817
774
|
return `${outputName.slice(0, -3)}.d.ts`;
|