refactor: replace grpc-reflection-js with grpc-js-reflection-client in grpc-client implementation

rm: comment

fix: type generation

feat: implement reflection client support for gRPC v1 and v1alpha in grpc-client

refactor: simplify reflection client handling in grpc-client by removing service list retrieval

refactor: enhance reflection client return structure in grpc-client to include service list

fix: lint
This commit is contained in:
sanish-bruno
2025-09-27 04:58:35 +05:30
parent 3b4e5686b8
commit b982f6db16
3 changed files with 65 additions and 71 deletions

53
package-lock.json generated
View File

@@ -8232,12 +8232,6 @@
"@types/node": "*"
}
},
"node_modules/@types/google-protobuf": {
"version": "3.15.12",
"resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.12.tgz",
"integrity": "sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==",
"license": "MIT"
},
"node_modules/@types/graceful-fs": {
"version": "4.1.9",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
@@ -8373,9 +8367,9 @@
"license": "MIT"
},
"node_modules/@types/lodash": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz",
"integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==",
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
"license": "MIT"
},
"node_modules/@types/lodash-es": {
@@ -8388,15 +8382,6 @@
"@types/lodash": "*"
}
},
"node_modules/@types/lodash.set": {
"version": "4.3.9",
"resolved": "https://registry.npmjs.org/@types/lodash.set/-/lodash.set-4.3.9.tgz",
"integrity": "sha512-KOxyNkZpbaggVmqbpr82N2tDVTx05/3/j0f50Es1prxrWB0XYf9p3QNxqcbWb7P1Q9wlvsUSlCFnwlPCIJ46PQ==",
"license": "MIT",
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/markdown-it": {
"version": "12.2.3",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
@@ -15182,12 +15167,6 @@
"csstype": "^3.0.10"
}
},
"node_modules/google-protobuf": {
"version": "3.21.4",
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.4.tgz",
"integrity": "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==",
"license": "(BSD-3-Clause AND Apache-2.0)"
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@@ -15312,20 +15291,18 @@
"node": ">= 6"
}
},
"node_modules/grpc-reflection-js": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/grpc-reflection-js/-/grpc-reflection-js-0.3.0.tgz",
"integrity": "sha512-3lhTlQluPxVgbowCXA3tAZC3RJW+GSOUkguLNYl1QffYRiutUB3RDfPkQFTcrCFJgNiIIxx+iJkr8s3uSp3zWA==",
"node_modules/grpc-js-reflection-client": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/grpc-js-reflection-client/-/grpc-js-reflection-client-1.3.0.tgz",
"integrity": "sha512-eJ5/m1pXpcheSjOGExktU69WPUKnL4Su3IxGJYYYjy3/w19vE8dH7Wi46G5T92bpM0eZWftjiM5HduX8CjPq9w==",
"license": "MIT",
"dependencies": {
"@types/google-protobuf": "^3.7.2",
"@types/lodash.set": "^4.3.6",
"google-protobuf": "^3.12.2",
"lodash.set": "^4.3.2",
"protobufjs": "^7.2.2"
"@types/lodash": "^4.17.15",
"lodash": "^4.17.21",
"protobufjs": "^7.4.0"
},
"peerDependencies": {
"@grpc/grpc-js": "^1.0.0"
"@grpc/grpc-js": "^1.12.6"
}
},
"node_modules/har-schema": {
@@ -18634,12 +18611,6 @@
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
"integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==",
"license": "MIT"
},
"node_modules/lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@@ -32129,7 +32100,7 @@
"@types/qs": "^6.9.18",
"axios": "^1.9.0",
"debug": "^4.4.3",
"grpc-reflection-js": "^0.3.0",
"grpc-js-reflection-client": "^1.3.0",
"is-ip": "^5.0.1",
"system-ca": "^2.0.1",
"tough-cookie": "^6.0.0",

View File

@@ -26,7 +26,7 @@
"@types/qs": "^6.9.18",
"axios": "^1.9.0",
"debug": "^4.4.3",
"grpc-reflection-js": "^0.3.0",
"grpc-js-reflection-client": "^1.3.0",
"is-ip": "^5.0.1",
"ws": "^8.18.3",
"system-ca": "^2.0.1",
@@ -53,4 +53,4 @@
"overrides": {
"rollup": "3.29.5"
}
}
}

View File

@@ -1,5 +1,5 @@
import { makeGenericClientConstructor, ChannelCredentials, Metadata } from '@grpc/grpc-js';
import * as grpcReflection from 'grpc-reflection-js';
import { makeGenericClientConstructor, ChannelCredentials, Metadata, status } from '@grpc/grpc-js';
import { GrpcReflection } from 'grpc-js-reflection-client';
import * as protoLoader from '@grpc/proto-loader';
import { generateGrpcSampleMessage } from './grpcMessageGenerator';
import * as tls from 'tls';
@@ -34,6 +34,8 @@ const configOptions = {
json: true
};
const reflectionServices = ['grpc.reflection.v1alpha.ServerReflection', 'grpc.reflection.v1.ServerReflection'];
const replaceTabsWithSpaces = (str, numSpaces = 2) => {
if (!str || !str.length || !isString(str)) {
return '';
@@ -172,6 +174,32 @@ class GrpcClient {
this.eventCallback = eventCallback;
}
/**
* Creates a reflection client that works for v1, v1alpha, or both.
*
* @param {string} host - host:port of the gRPC server
* @param {grpc.ChannelCredentials} credentials - defaults to insecure
* @param {grpc.ChannelOptions} options - channel options
* @returns {Promise<{ client: GrpcReflection, version: 'v1' | 'v1alpha' }>}
*/
async #getReflectionClient(host, credentials = ChannelCredentials.createInsecure(), options = {}) {
const makeClient = (version) => new GrpcReflection(host, credentials, options, version);
let client;
let services;
try {
client = makeClient('v1');
services = await client.listServices();
return { client, services };
} catch (e) {
console.warn(`gRPC reflection v1 failed:`, e);
}
client = makeClient('v1alpha');
services = await client.listServices();
return { client, services };
}
/**
* Get method type based on streaming configuration
*/
@@ -582,31 +610,29 @@ class GrpcClient {
});
try {
const client = new grpcReflection.Client(host, credentials, {}, metadata);
const { client, services } = await this.#getReflectionClient(host, credentials, {});
const methods = [];
const declarations = await client.listServices();
const methods = await Promise.all(
declarations.map(async (declaration) => {
const fileContainingSymbol = await client.fileContainingSymbol(declaration);
const descriptor = fileContainingSymbol.toDescriptor('proto3');
const protoDefinition = protoLoader.loadFileDescriptorSetFromObject(descriptor, configOptions);
for (const service of services) {
if (reflectionServices.includes(service)) {
continue;
}
const m = await client.listMethods(service);
methods.push(...m);
}
const serviceDefinition = protoDefinition[declaration];
if (!!serviceDefinition?.format) {
return [];
}
const methods = Object.values(serviceDefinition);
methods.forEach((method) => {
this.methods.set(method.path, method);
});
return methods;
})
);
const methodsWithType = methods.flat().map((method) => ({
...method,
type: this.#getMethodType(method)
}));
const methodsWithType = methods.map((method) => {
const { definition, ...rest } = method;
const modifiedMethod = {
...rest,
...definition
};
modifiedMethod.type = this.#getMethodType(modifiedMethod);
return modifiedMethod;
});
methodsWithType.forEach((method) => {
this.methods.set(method.path, method);
});
return methodsWithType;
} catch (error) {
console.error('Error in gRPC reflection:', error);
@@ -615,9 +641,6 @@ class GrpcClient {
}
}
/**
* Load methods from proto file
*/
async loadMethodsFromProtoFile(filePath, includeDirs = []) {
const protoDefinition = await protoLoader.load(filePath, { ...configOptions, includeDirs });
const methods = Object.values(protoDefinition)