ts-proto 1.164.2 → 1.165.1
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.markdown +12 -10
- package/build/generate-services.js +48 -19
- package/build/options.js +8 -3
- package/build/utils.js +9 -1
- package/package.json +2 -2
package/README.markdown
CHANGED
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
- [Highlights](#highlights)
|
|
20
20
|
- [Auto-Batching / N+1 Prevention](#auto-batching--n1-prevention)
|
|
21
21
|
- [Usage](#usage)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
- [Supported options](#supported-options)
|
|
23
|
+
- [NestJS Support](#nestjs-support)
|
|
24
|
+
- [Watch Mode](#watch-mode)
|
|
25
|
+
- [Basic gRPC implementation](#basic-grpc-implementation)
|
|
26
26
|
- [Sponsors](#sponsors)
|
|
27
27
|
- [Development](#development)
|
|
28
28
|
- [Assumptions](#assumptions)
|
|
@@ -121,8 +121,8 @@ plugins:
|
|
|
121
121
|
|
|
122
122
|
If you're using a modern TS setup with either `esModuleInterop` or running in an ESM environment, you'll need to pass `ts_proto_opt`s of:
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
- `esModuleInterop=true` if using `esModuleInterop` in your `tsconfig.json`, and
|
|
125
|
+
- `importSuffix=.js` if executing the generated ts-proto code in an ESM environment
|
|
126
126
|
|
|
127
127
|
# Goals
|
|
128
128
|
|
|
@@ -448,9 +448,11 @@ Generated code will be placed in the Gradle build directory.
|
|
|
448
448
|
|
|
449
449
|
- With `--ts_proto_opt=outputServices=false`, or `=none`, ts-proto will output NO service definitions.
|
|
450
450
|
|
|
451
|
-
- With `--ts_proto_opt=
|
|
451
|
+
- With `--ts_proto_opt=rpcBeforeRequest=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `beforeRequest(service: string, message: string, request: <RequestType>)`. It will will also automatically set `outputServices=default`. Each of the Service's methods will call `beforeRequest` before performing it's request.
|
|
452
452
|
|
|
453
|
-
- With `--ts_proto_opt=
|
|
453
|
+
- With `--ts_proto_opt=rpcAfterResponse=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `afterResponse(service: string, message: string, response: <ResponseType>)`. It will will also automatically set `outputServices=default`. Each of the Service's methods will call `afterResponse` before returning the response.
|
|
454
|
+
|
|
455
|
+
- With `--ts_proto_opt=rpcErrorHandler=true`, ts-proto will add a function definition to the Rpc interface definition with the signature: `handleError(service: string, message: string, error: Error)`. It will will also automatically set `outputServices=default`.
|
|
454
456
|
|
|
455
457
|
- With `--ts_proto_opt=useAbortSignal=true`, the generated services will accept an `AbortSignal` to cancel RPC calls.
|
|
456
458
|
|
|
@@ -611,12 +613,12 @@ This section describes how to contribute directly to ts-proto, i.e. it's not req
|
|
|
611
613
|
|
|
612
614
|
**Requirements**
|
|
613
615
|
|
|
614
|
-
- [Docker](https://www.docker.com)
|
|
616
|
+
- [Docker](https://www.docker.com)
|
|
615
617
|
- `yarn` — `npm install -g yarn`
|
|
616
618
|
|
|
617
619
|
**Setup**
|
|
618
620
|
|
|
619
|
-
The commands below assume you have **Docker** installed.
|
|
621
|
+
The commands below assume you have **Docker** installed. If you are using OS X, install **coreutils**, `brew install coreutils`.
|
|
620
622
|
|
|
621
623
|
- Check out the [repository]() for the latest code.
|
|
622
624
|
- Run `yarn install` to install the dependencies.
|
|
@@ -87,23 +87,32 @@ function generateRegularRpcMethod(ctx, methodDesc) {
|
|
|
87
87
|
];
|
|
88
88
|
const maybeCtx = options.context ? "ctx," : "";
|
|
89
89
|
const maybeAbortSignal = options.useAbortSignal ? "abortSignal || undefined," : "";
|
|
90
|
+
let errorHandler;
|
|
91
|
+
if (options.rpcErrorHandler) {
|
|
92
|
+
errorHandler = (0, ts_poet_1.code) `
|
|
93
|
+
if (error instanceof Error && this.rpc.handleError) {
|
|
94
|
+
return Promise.reject(this.rpc.handleError(this.service, "${methodDesc.name}", error));
|
|
95
|
+
}
|
|
96
|
+
return Promise.reject(error);
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
90
99
|
let encode = (0, ts_poet_1.code) `${rawInputType}.encode(request).finish()`;
|
|
91
100
|
let beforeRequest;
|
|
92
|
-
if (options.
|
|
101
|
+
if (options.rpcBeforeRequest) {
|
|
93
102
|
beforeRequest = (0, ts_poet_1.code) `
|
|
94
103
|
if (this.rpc.beforeRequest) {
|
|
95
|
-
this.rpc.beforeRequest(request);
|
|
104
|
+
this.rpc.beforeRequest(this.service, "${methodDesc.name}", request);
|
|
96
105
|
}`;
|
|
97
106
|
}
|
|
98
|
-
let decode = (0, ts_poet_1.code)
|
|
99
|
-
if (options.
|
|
100
|
-
decode = (0, ts_poet_1.code) `
|
|
107
|
+
let decode = (0, ts_poet_1.code) `${rawOutputType}.decode(${Reader}.create(data))`;
|
|
108
|
+
if (options.rpcAfterResponse) {
|
|
109
|
+
decode = (0, ts_poet_1.code) `
|
|
101
110
|
const response = ${rawOutputType}.decode(${Reader}.create(data));
|
|
102
111
|
if (this.rpc.afterResponse) {
|
|
103
|
-
this.rpc.afterResponse(response);
|
|
112
|
+
this.rpc.afterResponse(this.service, "${methodDesc.name}", response);
|
|
104
113
|
}
|
|
105
114
|
return response;
|
|
106
|
-
|
|
115
|
+
`;
|
|
107
116
|
}
|
|
108
117
|
// if (options.useDate && rawOutputType.toString().includes("Timestamp")) {
|
|
109
118
|
// decode = code`data => ${utils.fromTimestamp}(${rawOutputType}.decode(${Reader}.create(data)))`;
|
|
@@ -116,19 +125,13 @@ function generateRegularRpcMethod(ctx, methodDesc) {
|
|
|
116
125
|
encode = (0, ts_poet_1.code) `request.pipe(${(0, ts_poet_1.imp)("map@rxjs/operators")}(request => ${encode}))`;
|
|
117
126
|
}
|
|
118
127
|
}
|
|
128
|
+
const returnStatement = createDefaultServiceReturn(ctx, methodDesc, decode, errorHandler);
|
|
119
129
|
let returnVariable;
|
|
120
130
|
if (options.returnObservable || methodDesc.serverStreaming) {
|
|
121
131
|
returnVariable = "result";
|
|
122
|
-
if (options.useAsyncIterable) {
|
|
123
|
-
decode = (0, ts_poet_1.code) `${rawOutputType}.decodeTransform(result)`;
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
decode = (0, ts_poet_1.code) `result.pipe(${(0, ts_poet_1.imp)("map@rxjs/operators")}(${decode}))`;
|
|
127
|
-
}
|
|
128
132
|
}
|
|
129
133
|
else {
|
|
130
134
|
returnVariable = "promise";
|
|
131
|
-
decode = (0, ts_poet_1.code) `promise.then(${decode})`;
|
|
132
135
|
}
|
|
133
136
|
let rpcMethod;
|
|
134
137
|
if (methodDesc.clientStreaming && methodDesc.serverStreaming) {
|
|
@@ -155,10 +158,33 @@ function generateRegularRpcMethod(ctx, methodDesc) {
|
|
|
155
158
|
data,
|
|
156
159
|
${maybeAbortSignal}
|
|
157
160
|
);
|
|
158
|
-
return ${
|
|
161
|
+
return ${returnStatement};
|
|
159
162
|
}
|
|
160
163
|
`;
|
|
161
164
|
}
|
|
165
|
+
function createDefaultServiceReturn(ctx, methodDesc, decode, errorHandler) {
|
|
166
|
+
const { options } = ctx;
|
|
167
|
+
const rawOutputType = (0, types_1.responseType)(ctx, methodDesc, { keepValueType: true });
|
|
168
|
+
if (options.returnObservable || methodDesc.serverStreaming) {
|
|
169
|
+
if (options.useAsyncIterable) {
|
|
170
|
+
return (0, ts_poet_1.code) `${rawOutputType}.decodeTransform(result)`;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
return (0, ts_poet_1.code) `result.pipe(${(0, ts_poet_1.imp)("map@rxjs/operators")}(data => ${decode}))`;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (errorHandler) {
|
|
177
|
+
let tryBlock = decode;
|
|
178
|
+
if (!options.rpcAfterResponse) {
|
|
179
|
+
tryBlock = (0, ts_poet_1.code) `return ${decode}`;
|
|
180
|
+
}
|
|
181
|
+
return (0, ts_poet_1.code) `promise.then(data => { ${(0, utils_1.tryCatchBlock)(tryBlock, (0, ts_poet_1.code) `return Promise.reject(error);`)}}).catch((error) => { ${errorHandler} })`;
|
|
182
|
+
}
|
|
183
|
+
else if (options.rpcAfterResponse) {
|
|
184
|
+
return (0, ts_poet_1.code) `promise.then(data => { ${decode} } )`;
|
|
185
|
+
}
|
|
186
|
+
return (0, ts_poet_1.code) `promise.then(data => ${decode})`;
|
|
187
|
+
}
|
|
162
188
|
function generateServiceClientImpl(ctx, fileDesc, serviceDesc) {
|
|
163
189
|
const { options } = ctx;
|
|
164
190
|
const chunks = [];
|
|
@@ -302,11 +328,14 @@ function generateRpcType(ctx, hasStreamingMethods) {
|
|
|
302
328
|
const maybeAbortSignalParam = options.useAbortSignal ? "abortSignal?: AbortSignal," : "";
|
|
303
329
|
const methods = [[(0, ts_poet_1.code) `request`, (0, ts_poet_1.code) `Uint8Array`, (0, ts_poet_1.code) `Promise<Uint8Array>`]];
|
|
304
330
|
const additionalMethods = [];
|
|
305
|
-
if (options.
|
|
306
|
-
additionalMethods.push((0, ts_poet_1.code) `beforeRequest?<T extends { [k in keyof T]: unknown }>(request: T): void;`);
|
|
331
|
+
if (options.rpcBeforeRequest) {
|
|
332
|
+
additionalMethods.push((0, ts_poet_1.code) `beforeRequest?<T extends { [k in keyof T]: unknown }>(service: string, method: string, request: T): void;`);
|
|
333
|
+
}
|
|
334
|
+
if (options.rpcAfterResponse) {
|
|
335
|
+
additionalMethods.push((0, ts_poet_1.code) `afterResponse?<T extends { [k in keyof T]: unknown }>(service: string, method: string, response: T): void;`);
|
|
307
336
|
}
|
|
308
|
-
if (options.
|
|
309
|
-
additionalMethods.push((0, ts_poet_1.code) `
|
|
337
|
+
if (options.rpcErrorHandler) {
|
|
338
|
+
additionalMethods.push((0, ts_poet_1.code) `handleError?(service: string, method: string, error: Error): Error;`);
|
|
310
339
|
}
|
|
311
340
|
if (hasStreamingMethods) {
|
|
312
341
|
const observable = (0, types_1.observableType)(ctx, true);
|
package/build/options.js
CHANGED
|
@@ -93,8 +93,9 @@ function defaultOptions() {
|
|
|
93
93
|
outputExtensions: false,
|
|
94
94
|
outputIndex: false,
|
|
95
95
|
M: {},
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
rpcBeforeRequest: false,
|
|
97
|
+
rpcAfterResponse: false,
|
|
98
|
+
rpcErrorHandler: false,
|
|
98
99
|
};
|
|
99
100
|
}
|
|
100
101
|
exports.defaultOptions = defaultOptions;
|
|
@@ -183,8 +184,12 @@ function optionsFromParameter(parameter) {
|
|
|
183
184
|
if (options.outputIndex) {
|
|
184
185
|
options.exportCommonSymbols = false;
|
|
185
186
|
}
|
|
186
|
-
if (options.
|
|
187
|
+
if (options.rpcBeforeRequest || options.rpcAfterResponse || options.rpcErrorHandler) {
|
|
188
|
+
const includesGeneric = options.outputServices.includes(ServiceOption.GENERIC);
|
|
187
189
|
options.outputServices = [ServiceOption.DEFAULT];
|
|
190
|
+
if (includesGeneric) {
|
|
191
|
+
options.outputServices.push(ServiceOption.GENERIC);
|
|
192
|
+
}
|
|
188
193
|
}
|
|
189
194
|
if (options.unrecognizedEnumValue) {
|
|
190
195
|
// Make sure to cast number options to an actual number
|
package/build/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.impProto = exports.impFile = exports.getPropertyAccessor = exports.safeAccessor = exports.getFieldName = exports.getFieldJsonName = exports.FormattedMethodDescriptor = exports.assertInstanceOf = exports.maybePrefixPackage = exports.prefixDisableLinter = exports.maybeAddComment = exports.upperFirst = exports.lowerFirst = exports.singular = exports.fail = exports.readToBuffer = exports.generateIndexFiles = exports.protoFilesToGenerate = void 0;
|
|
3
|
+
exports.tryCatchBlock = exports.impProto = exports.impFile = exports.getPropertyAccessor = exports.safeAccessor = exports.getFieldName = exports.getFieldJsonName = exports.FormattedMethodDescriptor = exports.assertInstanceOf = exports.maybePrefixPackage = exports.prefixDisableLinter = exports.maybeAddComment = exports.upperFirst = exports.lowerFirst = exports.singular = exports.fail = exports.readToBuffer = exports.generateIndexFiles = exports.protoFilesToGenerate = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const ts_poet_1 = require("ts-poet");
|
|
6
6
|
const options_1 = require("./options");
|
|
@@ -243,3 +243,11 @@ function impProto(options, module, type) {
|
|
|
243
243
|
return (0, ts_poet_1.imp)(`${prefix}${type}@./${module}${options.fileSuffix}${options.importSuffix}`);
|
|
244
244
|
}
|
|
245
245
|
exports.impProto = impProto;
|
|
246
|
+
function tryCatchBlock(tryBlock, handleErrorBlock) {
|
|
247
|
+
return (0, ts_poet_1.code) `try {
|
|
248
|
+
${tryBlock}
|
|
249
|
+
} catch (error) {
|
|
250
|
+
${handleErrorBlock}
|
|
251
|
+
}`;
|
|
252
|
+
}
|
|
253
|
+
exports.tryCatchBlock = tryCatchBlock;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-proto",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.165.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/plugin.js",
|
|
6
6
|
"repository": "github:stephenh/ts-proto",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"proto2bin-node": "docker compose run --rm node update-bins.sh",
|
|
16
16
|
"proto2pbjs": "docker compose run --rm protoc pbjs.sh",
|
|
17
17
|
"bin2ts": "docker compose run --rm protoc codegen.sh",
|
|
18
|
-
"test": "yarn jest -c jest.config.js
|
|
18
|
+
"test": "yarn jest -c jest.config.js",
|
|
19
19
|
"tsc:check": "./tsc-check.sh tsconfig.json tests/tsconfig.json integration/tsconfig.json integration/tsconfig.proto.json protos/tsconfig.json",
|
|
20
20
|
"format": "prettier --write {src,tests}/**/*.ts integration/*.ts",
|
|
21
21
|
"format:check": "prettier --list-different {src,tests}/**/*.ts",
|