ts-proto 1.164.1 → 1.165.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.markdown +10 -8
- package/build/generate-grpc-web.js +20 -14
- 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
|
|
|
@@ -301,13 +301,6 @@ function createObservableUnaryMethod(ctx) {
|
|
|
301
301
|
function createInvokeMethod(ctx) {
|
|
302
302
|
const { options } = ctx;
|
|
303
303
|
const { useAbortSignal } = options;
|
|
304
|
-
const maybeAbortSignal = useAbortSignal
|
|
305
|
-
? `
|
|
306
|
-
if (abortSignal) abortSignal.addEventListener("abort", () => {
|
|
307
|
-
observer.error(abortSignal.reason);
|
|
308
|
-
client.close();
|
|
309
|
-
});`
|
|
310
|
-
: "";
|
|
311
304
|
return (0, ts_poet_1.code) `
|
|
312
305
|
invoke<T extends UnaryMethodDefinitionish>(
|
|
313
306
|
methodDesc: T,
|
|
@@ -344,14 +337,27 @@ function createInvokeMethod(ctx) {
|
|
|
344
337
|
}
|
|
345
338
|
},
|
|
346
339
|
});
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
340
|
+
${useAbortSignal
|
|
341
|
+
? `
|
|
342
|
+
if (abortSignal) {
|
|
343
|
+
const abort = () => {
|
|
344
|
+
observer.error(abortSignal.reason);
|
|
345
|
+
client.close();
|
|
346
|
+
};
|
|
347
|
+
abortSignal.addEventListener("abort", abort);
|
|
348
|
+
observer.add(() => {
|
|
349
|
+
if (abortSignal.aborted) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
353
352
|
|
|
354
|
-
|
|
353
|
+
abortSignal.removeEventListener('abort', abort);
|
|
354
|
+
client.close();
|
|
355
|
+
});
|
|
356
|
+
} else {
|
|
357
|
+
observer.add(() => client.close());
|
|
358
|
+
}
|
|
359
|
+
`
|
|
360
|
+
: `observer.add(() => client.close());`}
|
|
355
361
|
});
|
|
356
362
|
upStream();
|
|
357
363
|
}).pipe(${share}());
|
|
@@ -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.0",
|
|
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",
|