ts-proto 1.84.0 → 1.85.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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [1.85.0](https://github.com/stephenh/ts-proto/compare/v1.84.0...v1.85.0) (2021-11-02)
2
+
3
+
4
+ ### Features
5
+
6
+ * Streaming support ([#373](https://github.com/stephenh/ts-proto/issues/373)) ([459b94f](https://github.com/stephenh/ts-proto/commit/459b94f5b2988d58d186461332e888c3e511603a))
7
+
1
8
  # [1.84.0](https://github.com/stephenh/ts-proto/compare/v1.83.3...v1.84.0) (2021-11-02)
2
9
 
3
10
 
@@ -43,9 +43,7 @@ function generateRpcMethod(ctx, serviceDesc, methodDesc) {
43
43
  const { options, utils } = ctx;
44
44
  const inputType = types_1.requestType(ctx, methodDesc);
45
45
  const partialInputType = ts_poet_1.code `${utils.DeepPartial}<${inputType}>`;
46
- const returns = options.returnObservable || methodDesc.serverStreaming
47
- ? types_1.responseObservable(ctx, methodDesc)
48
- : types_1.responsePromise(ctx, methodDesc);
46
+ const returns = types_1.responsePromiseOrObservable(ctx, methodDesc);
49
47
  const method = methodDesc.serverStreaming ? 'invoke' : 'unary';
50
48
  return ts_poet_1.code `
51
49
  ${methodDesc.formattedName}(
@@ -55,15 +55,7 @@ function generateService(ctx, fileDesc, sourceInfo, serviceDesc) {
55
55
  if (options.addNestjsRestParameter) {
56
56
  params.push(ts_poet_1.code `...rest: any`);
57
57
  }
58
- // Return observable for interface only configuration, passing returnObservable=true and methodDesc.serverStreaming=true
59
- let returnType;
60
- if (options.returnObservable || methodDesc.serverStreaming) {
61
- returnType = types_1.responseObservable(ctx, methodDesc);
62
- }
63
- else {
64
- returnType = types_1.responsePromise(ctx, methodDesc);
65
- }
66
- chunks.push(ts_poet_1.code `${methodDesc.formattedName}(${ts_poet_1.joinCode(params, { on: ',' })}): ${returnType};`);
58
+ chunks.push(ts_poet_1.code `${methodDesc.formattedName}(${ts_poet_1.joinCode(params, { on: ',' })}): ${types_1.responsePromiseOrObservable(ctx, methodDesc)};`);
67
59
  // If this is a batch method, auto-generate the singular version of it
68
60
  if (options.context) {
69
61
  const batchMethod = types_1.detectBatchMethod(ctx, fileDesc, serviceDesc, methodDesc);
@@ -83,22 +75,50 @@ function generateRegularRpcMethod(ctx, fileDesc, serviceDesc, methodDesc) {
83
75
  utils_1.assertInstanceOf(methodDesc, utils_1.FormattedMethodDescriptor);
84
76
  const { options } = ctx;
85
77
  const Reader = ts_poet_1.imp('Reader@protobufjs/minimal');
78
+ const rawInputType = types_1.rawRequestType(ctx, methodDesc);
86
79
  const inputType = types_1.requestType(ctx, methodDesc);
87
80
  const outputType = types_1.responseType(ctx, methodDesc);
88
81
  const params = [...(options.context ? [ts_poet_1.code `ctx: Context`] : []), ts_poet_1.code `request: ${inputType}`];
89
82
  const maybeCtx = options.context ? 'ctx,' : '';
83
+ let encode = ts_poet_1.code `${rawInputType}.encode(request).finish()`;
84
+ let decode = ts_poet_1.code `data => ${outputType}.decode(new ${Reader}(data))`;
85
+ if (methodDesc.clientStreaming) {
86
+ encode = ts_poet_1.code `request.pipe(${ts_poet_1.imp('map@rxjs/operators')}(request => ${encode}))`;
87
+ }
88
+ let returnVariable;
89
+ if (options.returnObservable || methodDesc.serverStreaming) {
90
+ returnVariable = 'result';
91
+ decode = ts_poet_1.code `result.pipe(${ts_poet_1.imp('map@rxjs/operators')}(${decode}))`;
92
+ }
93
+ else {
94
+ returnVariable = 'promise';
95
+ decode = ts_poet_1.code `promise.then(${decode})`;
96
+ }
97
+ let rpcMethod;
98
+ if (methodDesc.clientStreaming && methodDesc.serverStreaming) {
99
+ rpcMethod = 'bidirectionalStreamingRequest';
100
+ }
101
+ else if (methodDesc.serverStreaming) {
102
+ rpcMethod = 'serverStreamingRequest';
103
+ }
104
+ else if (methodDesc.clientStreaming) {
105
+ rpcMethod = 'clientStreamingRequest';
106
+ }
107
+ else {
108
+ rpcMethod = 'request';
109
+ }
90
110
  return ts_poet_1.code `
91
111
  ${methodDesc.formattedName}(
92
112
  ${ts_poet_1.joinCode(params, { on: ',' })}
93
- ): ${types_1.responsePromise(ctx, methodDesc)} {
94
- const data = ${inputType}.encode(request).finish();
95
- const promise = this.rpc.request(
113
+ ): ${types_1.responsePromiseOrObservable(ctx, methodDesc)} {
114
+ const data = ${encode};
115
+ const ${returnVariable} = this.rpc.${rpcMethod}(
96
116
  ${maybeCtx}
97
117
  "${utils_1.maybePrefixPackage(fileDesc, serviceDesc.name)}",
98
118
  "${methodDesc.name}",
99
119
  data
100
120
  );
101
- return promise.then(data => ${outputType}.decode(new ${Reader}(data)));
121
+ return ${decode};
102
122
  }
103
123
  `;
104
124
  }
@@ -217,24 +237,41 @@ function generateCachingRpcMethod(ctx, fileDesc, serviceDesc, methodDesc) {
217
237
  *
218
238
  * This lets clients pass in their own request-promise-ish client.
219
239
  *
240
+ * This also requires clientStreamingRequest, serverStreamingRequest and
241
+ * bidirectionalStreamingRequest methods if any of the RPCs is streaming.
242
+ *
220
243
  * We don't export this because if a project uses multiple `*.proto` files,
221
244
  * we don't want our the barrel imports in `index.ts` to have multiple `Rpc`
222
245
  * types.
223
246
  */
224
- function generateRpcType(ctx) {
247
+ function generateRpcType(ctx, hasStreamingMethods) {
225
248
  const { options } = ctx;
226
249
  const maybeContext = options.context ? '<Context>' : '';
227
250
  const maybeContextParam = options.context ? 'ctx: Context,' : '';
228
- return ts_poet_1.code `
229
- interface Rpc${maybeContext} {
230
- request(
251
+ const methods = [[ts_poet_1.code `request`, ts_poet_1.code `Uint8Array`, ts_poet_1.code `Promise<Uint8Array>`]];
252
+ if (hasStreamingMethods) {
253
+ const observable = ts_poet_1.imp('Observable@rxjs');
254
+ methods.push([ts_poet_1.code `clientStreamingRequest`, ts_poet_1.code `${observable}<Uint8Array>`, ts_poet_1.code `Promise<Uint8Array>`]);
255
+ methods.push([ts_poet_1.code `serverStreamingRequest`, ts_poet_1.code `Uint8Array`, ts_poet_1.code `${observable}<Uint8Array>`]);
256
+ methods.push([
257
+ ts_poet_1.code `bidirectionalStreamingRequest`,
258
+ ts_poet_1.code `${observable}<Uint8Array>`,
259
+ ts_poet_1.code `${observable}<Uint8Array>`,
260
+ ]);
261
+ }
262
+ const chunks = [];
263
+ chunks.push(ts_poet_1.code ` interface Rpc${maybeContext} {`);
264
+ methods.forEach((method) => {
265
+ chunks.push(ts_poet_1.code `
266
+ ${method[0]}(
231
267
  ${maybeContextParam}
232
268
  service: string,
233
269
  method: string,
234
- data: Uint8Array
235
- ): Promise<Uint8Array>;
236
- }
237
- `;
270
+ data: ${method[1]}
271
+ ): ${method[2]};`);
272
+ });
273
+ chunks.push(ts_poet_1.code ` }`);
274
+ return ts_poet_1.joinCode(chunks, { on: '\n' });
238
275
  }
239
276
  exports.generateRpcType = generateRpcType;
240
277
  function generateDataLoadersType() {
package/build/main.js CHANGED
@@ -91,6 +91,7 @@ function generateFile(ctx, fileDesc) {
91
91
  }
92
92
  }, options);
93
93
  }
94
+ let hasServerStreamingMethods = false;
94
95
  let hasStreamingMethods = false;
95
96
  visit_1.visitServices(fileDesc, sourceInfo, (serviceDesc, sInfo) => {
96
97
  if (options.nestJs) {
@@ -126,18 +127,23 @@ function generateFile(ctx, fileDesc) {
126
127
  serviceDesc.method.forEach((method) => {
127
128
  chunks.push(generate_grpc_web_1.generateGrpcMethodDesc(ctx, serviceDesc, method));
128
129
  if (method.serverStreaming) {
129
- hasStreamingMethods = true;
130
+ hasServerStreamingMethods = true;
130
131
  }
131
132
  });
132
133
  }
133
134
  }
135
+ serviceDesc.method.forEach((methodDesc, index) => {
136
+ if (methodDesc.serverStreaming || methodDesc.clientStreaming) {
137
+ hasStreamingMethods = true;
138
+ }
139
+ });
134
140
  });
135
141
  if (options.outputServices === options_1.ServiceOption.DEFAULT && options.outputClientImpl && fileDesc.service.length > 0) {
136
142
  if (options.outputClientImpl === true) {
137
- chunks.push(generate_services_1.generateRpcType(ctx));
143
+ chunks.push(generate_services_1.generateRpcType(ctx, hasStreamingMethods));
138
144
  }
139
145
  else if (options.outputClientImpl === 'grpc-web') {
140
- chunks.push(generate_grpc_web_1.addGrpcWebMisc(ctx, hasStreamingMethods));
146
+ chunks.push(generate_grpc_web_1.addGrpcWebMisc(ctx, hasServerStreamingMethods));
141
147
  }
142
148
  }
143
149
  if (options.context) {
package/build/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.detectBatchMethod = exports.responseObservable = exports.responsePromise = exports.responseType = exports.requestType = exports.detectMapType = exports.toTypeName = exports.getEnumMethod = exports.messageToTypeName = exports.wrapperTypeName = exports.valueTypeName = exports.isEmptyType = exports.isLongValueType = exports.isBytesValueType = exports.isValueType = exports.isTimestamp = exports.isMapType = exports.isLong = exports.isRepeated = exports.isWithinOneOfThatShouldBeUnion = exports.isWithinOneOf = exports.isEnum = exports.isMessage = exports.isBytes = exports.isPrimitive = exports.isScalar = exports.createTypeMap = exports.notDefaultCheck = exports.defaultValue = exports.packedType = exports.toReaderCall = exports.basicTypeName = exports.basicLongWireType = exports.basicWireType = void 0;
3
+ exports.detectBatchMethod = exports.responsePromiseOrObservable = exports.responseObservable = exports.responsePromise = exports.responseType = exports.requestType = exports.rawRequestType = exports.detectMapType = exports.toTypeName = exports.getEnumMethod = exports.messageToTypeName = exports.wrapperTypeName = exports.valueTypeName = exports.isEmptyType = exports.isLongValueType = exports.isBytesValueType = exports.isValueType = exports.isTimestamp = exports.isMapType = exports.isLong = exports.isRepeated = exports.isWithinOneOfThatShouldBeUnion = exports.isWithinOneOf = exports.isEnum = exports.isMessage = exports.isBytes = exports.isPrimitive = exports.isScalar = exports.createTypeMap = exports.notDefaultCheck = exports.defaultValue = exports.packedType = exports.toReaderCall = exports.basicTypeName = exports.basicLongWireType = exports.basicWireType = void 0;
4
4
  const ts_proto_descriptors_1 = require("ts-proto-descriptors");
5
5
  const ts_poet_1 = require("ts-poet");
6
6
  const options_1 = require("./options");
@@ -512,8 +512,12 @@ function detectMapType(ctx, messageDesc, fieldDesc) {
512
512
  return undefined;
513
513
  }
514
514
  exports.detectMapType = detectMapType;
515
+ function rawRequestType(ctx, methodDesc) {
516
+ return messageToTypeName(ctx, methodDesc.inputType);
517
+ }
518
+ exports.rawRequestType = rawRequestType;
515
519
  function requestType(ctx, methodDesc) {
516
- let typeName = messageToTypeName(ctx, methodDesc.inputType);
520
+ let typeName = rawRequestType(ctx, methodDesc);
517
521
  if (methodDesc.clientStreaming) {
518
522
  return ts_poet_1.code `${ts_poet_1.imp('Observable@rxjs')}<${typeName}>`;
519
523
  }
@@ -532,6 +536,14 @@ function responseObservable(ctx, methodDesc) {
532
536
  return ts_poet_1.code `${ts_poet_1.imp('Observable@rxjs')}<${responseType(ctx, methodDesc)}>`;
533
537
  }
534
538
  exports.responseObservable = responseObservable;
539
+ function responsePromiseOrObservable(ctx, methodDesc) {
540
+ const { options } = ctx;
541
+ if (options.returnObservable || methodDesc.serverStreaming) {
542
+ return responseObservable(ctx, methodDesc);
543
+ }
544
+ return responsePromise(ctx, methodDesc);
545
+ }
546
+ exports.responsePromiseOrObservable = responsePromiseOrObservable;
535
547
  function detectBatchMethod(ctx, fileDesc, serviceDesc, methodDesc) {
536
548
  const { typeMap } = ctx;
537
549
  const nameMatches = methodDesc.name.startsWith('Batch');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.84.0",
3
+ "version": "1.85.0",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",