Socket
Socket
Sign inDemoInstall

@grpc/grpc-js

Package Overview
Dependencies
Maintainers
3
Versions
178
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@grpc/grpc-js - npm Package Compare versions

Comparing version 0.5.2 to 0.5.3

build/src/backoff-timeout.d.ts

8

build/src/call-stream.js

@@ -270,2 +270,10 @@ "use strict";

});
/* If the underlying TLS or TCP connection closes, we want to end the
* call with an UNAVAILABLE status to match the behavior of the other
* library. In this handler we don't wait for trailers before ending the
* call. This should ensure that this endCall happens sooner than the one
* in the stream.on('close', ...) handler. */
stream.session.socket.on('close', () => {
this.endCall({ code: constants_1.Status.UNAVAILABLE, details: 'Connection dropped', metadata: new metadata_1.Metadata() });
});
if (!this.pendingRead) {

@@ -272,0 +280,0 @@ stream.pause();

5

build/src/index.d.ts

@@ -11,5 +11,6 @@ /// <reference types="node" />

import { Metadata } from './metadata';
import { Server } from './server';
import { Server, UntypedHandleCall, UntypedServiceImplementation } from './server';
import { KeyCertPair, ServerCredentials } from './server-credentials';
import { StatusBuilder } from './status-builder';
import { ServerUnaryCall, ServerReadableStream, ServerWritableStream, ServerDuplexStream } from './server-call';
export interface OAuth2Client {

@@ -39,3 +40,3 @@ getRequestMetadata: (url: string, callback: (err: Error | null, headers?: {

export declare const waitForClientReady: (client: Client, deadline: Deadline, callback: (error?: Error | undefined) => void) => void;
export { ChannelCredentials, CallCredentials, Deadline, Serialize as serialize, Deserialize as deserialize, ClientUnaryCall, ClientReadableStream, ClientWritableStream, ClientDuplexStream, CallOptions, StatusObject, ServiceError, };
export { ChannelCredentials, CallCredentials, Deadline, Serialize as serialize, Deserialize as deserialize, ClientUnaryCall, ClientReadableStream, ClientWritableStream, ClientDuplexStream, CallOptions, StatusObject, ServiceError, ServerUnaryCall, ServerReadableStream, ServerWritableStream, ServerDuplexStream, UntypedHandleCall, UntypedServiceImplementation };
export declare type Call = ClientUnaryCall | ClientReadableStream<any> | ClientWritableStream<any> | ClientDuplexStream<any, any>;

@@ -42,0 +43,0 @@ export declare type MetadataListener = (metadata: Metadata, next: Function) => void;

@@ -19,5 +19,2 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
/* This file is an implementation of gRFC A24:
* https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md */
const util_1 = require("util");
/* In these functions we assume the input came from a JSON object. Therefore we

@@ -27,3 +24,3 @@ * expect that the prototype is uninteresting and that `in` can be used

function validateXdsConfig(xds) {
if (!('balancerName' in xds) || !util_1.isString(xds.balancerName)) {
if (!('balancerName' in xds) || typeof xds.balancerName !== 'string') {
throw new Error('Invalid xds config: invalid balancerName');

@@ -34,6 +31,6 @@ }

childPolicy: [],
fallbackPolicy: []
fallbackPolicy: [],
};
if ('childPolicy' in xds) {
if (!util_1.isArray(xds.childPolicy)) {
if (!Array.isArray(xds.childPolicy)) {
throw new Error('Invalid xds config: invalid childPolicy');

@@ -46,3 +43,3 @@ }

if ('fallbackPolicy' in xds) {
if (!util_1.isArray(xds.fallbackPolicy)) {
if (!Array.isArray(xds.fallbackPolicy)) {
throw new Error('Invalid xds config: invalid fallbackPolicy');

@@ -58,6 +55,6 @@ }

const grpcLbConfig = {
childPolicy: []
childPolicy: [],
};
if ('childPolicy' in grpclb) {
if (!util_1.isArray(grpclb.childPolicy)) {
if (!Array.isArray(grpclb.childPolicy)) {
throw new Error('Invalid xds config: invalid childPolicy');

@@ -64,0 +61,0 @@ }

4

build/src/resolver-dns.d.ts

@@ -0,1 +1,5 @@

/**
* Set up the DNS resolver class by registering it as the handler for the
* "dns:" prefix and as the default resolver.
*/
export declare function setup(): void;

@@ -20,18 +20,56 @@ "use strict";

const dns = require("dns");
const semver = require("semver");
const util = require("util");
const service_config_1 = require("./service-config");
const constants_1 = require("./constants");
const metadata_1 = require("./metadata");
/* These regular expressions match IP addresses with optional ports in different
* formats. In each case, capture group 1 contains the address, and capture
* group 2 contains the port number, if present */
const IPv4_REGEX = /^(\d{1,3}(?:\.\d{1,3}){3})(?::(\d+))?$/;
const IPv6_REGEX = /^([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)$/i;
const IPv6_BRACKET_REGEX = /^\[([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)\](?::(\d+))?$/i;
/**
* Matches 4 groups of up to 3 digits each, separated by periods, optionally
* followed by a colon and a number.
*/
const IPV4_REGEX = /^(\d{1,3}(?:\.\d{1,3}){3})(?::(\d+))?$/;
/**
* Matches any number of groups of up to 4 hex digits (case insensitive)
* separated by 1 or more colons. This variant does not match a port number.
*/
const IPV6_REGEX = /^([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)$/i;
/**
* Matches the same as the IPv6_REGEX, surrounded by square brackets, and
* optionally followed by a colon and a number.
*/
const IPV6_BRACKET_REGEX = /^\[([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)\](?::(\d+))?$/i;
/**
* Matches `[dns:][//authority/]host[:port]`, where `authority` and `host` are
* both arbitrary sequences of alphanumeric characters and `port` is a sequence
* of digits. Group 1 contains the hostname and group 2 contains the port
* number if provided.
*/
const DNS_REGEX = /^(?:dns:)?(?:\/\/\w+\/)?(\w+)(?::(\d+))?$/;
/**
* The default TCP port to connect to if not explicitly specified in the target.
*/
const DEFAULT_PORT = '443';
/**
* The range of Node versions in which the Node issue
* https://github.com/nodejs/node/issues/28216 has been fixed. In other
* versions, IPv6 literal addresses cannot be used to establish HTTP/2
* connections.
*/
const IPV6_SUPPORT_RANGE = '>= 12.6';
const resolve4Promise = util.promisify(dns.resolve4);
const resolve6Promise = util.promisify(dns.resolve6);
/**
* Attempt to parse a target string as an IP address
* @param target
* @return An "IP:port" string if parsing was successful, `null` otherwise
*/
function parseIP(target) {
/* These three regular expressions are all mutually exclusive, so we just
* want the first one that matches the target string, if any do. */
const match = IPv4_REGEX.exec(target) || IPv6_REGEX.exec(target) || IPv6_BRACKET_REGEX.exec(target);
const match = IPV4_REGEX.exec(target) ||
IPV6_REGEX.exec(target) ||
IPV6_BRACKET_REGEX.exec(target);
if (match === null) {

@@ -50,6 +88,10 @@ return null;

}
/**
* Merge any number of arrays into a single alternating array
* @param arrays
*/
function mergeArrays(...arrays) {
const result = [];
for (let i = 0; i < Math.max.apply(null, arrays.map((array) => array.length)); i++) {
for (let array of arrays) {
for (let i = 0; i < Math.max.apply(null, arrays.map(array => array.length)); i++) {
for (const array of arrays) {
if (i < array.length) {

@@ -62,2 +104,5 @@ result.push(array[i]);

}
/**
* Resolver implementation that handles DNS names and IP addresses.
*/
class DnsResolver {

@@ -86,4 +131,7 @@ constructor(target, listener) {

this.percentage = Math.random() * 100;
this.startResolution();
}
/**
* If the target is an IP address, just provide that address as a result.
* Otherwise, initiate A, AAAA, and TXT
*/
startResolution() {

@@ -98,5 +146,14 @@ if (this.ipResult !== null) {

const hostname = this.dnsHostname;
const Aresult = resolve4Promise(hostname);
const AAAAresult = resolve6Promise(hostname);
const TXTresult = new Promise((resolve, reject) => {
const aResult = resolve4Promise(hostname);
let aaaaResult;
if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) {
aaaaResult = resolve6Promise(hostname);
}
else {
aaaaResult = Promise.resolve([]);
}
/* We handle the TXT query promise differently than the others because
* the name resolution attempt as a whole is a success even if the TXT
* lookup fails */
const txtResult = new Promise((resolve, reject) => {
dns.resolveTxt(hostname, (err, records) => {

@@ -111,23 +168,37 @@ if (err) {

});
this.pendingResultPromise = Promise.all([Aresult, AAAAresult, TXTresult]);
this.pendingResultPromise.then(([Arecord, AAAArecord, TXTrecord]) => {
this.pendingResultPromise = Promise.all([aResult, aaaaResult, txtResult]);
this.pendingResultPromise.then(([aRecord, aaaaRecord, txtRecord]) => {
this.pendingResultPromise = null;
const allAddresses = mergeArrays(AAAArecord, Arecord);
aRecord = aRecord.map(value => `${value}:${this.port}`);
aaaaRecord = aaaaRecord.map(value => `[${value}]:${this.port}`);
const allAddresses = mergeArrays(aaaaRecord, aRecord);
let serviceConfig = null;
let serviceConfigError = null;
if (TXTrecord instanceof Error) {
serviceConfigError = TXTrecord;
if (txtRecord instanceof Error) {
serviceConfigError = {
code: constants_1.Status.UNAVAILABLE,
details: 'TXT query failed',
metadata: new metadata_1.Metadata(),
};
}
else {
try {
serviceConfig = service_config_1.extractAndSelectServiceConfig(TXTrecord, this.percentage);
serviceConfig = service_config_1.extractAndSelectServiceConfig(txtRecord, this.percentage);
}
catch (err) {
serviceConfigError = err;
serviceConfigError = {
code: constants_1.Status.UNAVAILABLE,
details: 'Parsing service config failed',
metadata: new metadata_1.Metadata(),
};
}
}
this.listener.onSuccessfulResolution(allAddresses, serviceConfig, serviceConfigError);
}, (err) => {
}, err => {
this.pendingResultPromise = null;
this.listener.onError(err);
this.listener.onError({
code: constants_1.Status.UNAVAILABLE,
details: 'Name resolution failed',
metadata: new metadata_1.Metadata(),
});
});

@@ -141,3 +212,25 @@ }

}
/**
* Get the default authority for the given target. For IP targets, that is
* the IP address. For DNS targets, it is the hostname.
* @param target
*/
static getDefaultAuthority(target) {
const ipMatch = IPV4_REGEX.exec(target) ||
IPV6_REGEX.exec(target) ||
IPV6_BRACKET_REGEX.exec(target);
if (ipMatch) {
return ipMatch[1];
}
const dnsMatch = DNS_REGEX.exec(target);
if (dnsMatch) {
return dnsMatch[1];
}
throw new Error(`Failed to parse target ${target}`);
}
}
/**
* Set up the DNS resolver class by registering it as the handler for the
* "dns:" prefix and as the default resolver.
*/
function setup() {

@@ -144,0 +237,0 @@ resolver_1.registerResolver('dns:', DnsResolver);

@@ -1,8 +0,35 @@

import { ServiceError } from "./call";
import { ServiceConfig } from "./service-config";
import { ServiceConfig } from './service-config';
import { StatusObject } from './call-stream';
/**
* A listener object passed to the resolver's constructor that provides name
* resolution updates back to the resolver's owner.
*/
export interface ResolverListener {
onSuccessfulResolution(addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: Error | null): void;
onError(error: ServiceError): void;
/**
* Called whenever the resolver has new name resolution results to report
* @param addressList The new list of backend addresses
* @param serviceConfig The new service configuration corresponding to the
* `addressList`. Will be `null` if no service configuration was
* retrieved or if the service configuration was invalid
* @param serviceConfigError If non-`null`, indicates that the retrieved
* service configuration was invalid
*/
onSuccessfulResolution(addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null): void;
/**
* Called whenever a name resolution attempt fails.
* @param error Describes how resolution failed
*/
onError(error: StatusObject): void;
}
/**
* A resolver class that handles one or more of the name syntax schemes defined
* in the [gRPC Name Resolution document](https://github.com/grpc/grpc/blob/master/doc/naming.md)
*/
export interface Resolver {
/**
* Indicates that the caller wants new name resolution data. Calling this
* function may eventually result in calling one of the `ResolverListener`
* functions, but that is not guaranteed. Those functions will never be
* called synchronously with the constructor or updateResolution.
*/
updateResolution(): void;

@@ -12,5 +39,37 @@ }

new (target: string, listener: ResolverListener): Resolver;
/**
* Get the default authority for a target. This loosely corresponds to that
* target's hostname. Throws an error if this resolver class cannot parse the
* `target`.
* @param target
*/
getDefaultAuthority(target: string): string;
}
/**
* Register a resolver class to handle target names prefixed with the `prefix`
* string. This prefix should correspond to a URI scheme name listed in the
* [gRPC Name Resolution document](https://github.com/grpc/grpc/blob/master/doc/naming.md)
* @param prefix
* @param resolverClass
*/
export declare function registerResolver(prefix: string, resolverClass: ResolverConstructor): void;
/**
* Register a default resolver to handle target names that do not start with
* any registered prefix.
* @param resolverClass
*/
export declare function registerDefaultResolver(resolverClass: ResolverConstructor): void;
/**
* Create a name resolver for the specified target, if possible. Throws an
* error if no such name resolver can be created.
* @param target
* @param listener
*/
export declare function createResolver(target: string, listener: ResolverListener): Resolver;
/**
* Get the default authority for the specified target, if possible. Throws an
* error if no registered name resolver can parse that target string.
* @param target
*/
export declare function getDefaultAuthority(target: string): string;
export declare function registerAll(): void;

@@ -19,4 +19,12 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const resolver_dns = require("./resolver-dns");
const registeredResolvers = {};
let defaultResolver = null;
/**
* Register a resolver class to handle target names prefixed with the `prefix`
* string. This prefix should correspond to a URI scheme name listed in the
* [gRPC Name Resolution document](https://github.com/grpc/grpc/blob/master/doc/naming.md)
* @param prefix
* @param resolverClass
*/
function registerResolver(prefix, resolverClass) {

@@ -26,2 +34,7 @@ registeredResolvers[prefix] = resolverClass;

exports.registerResolver = registerResolver;
/**
* Register a default resolver to handle target names that do not start with
* any registered prefix.
* @param resolverClass
*/
function registerDefaultResolver(resolverClass) {

@@ -31,2 +44,8 @@ defaultResolver = resolverClass;

exports.registerDefaultResolver = registerDefaultResolver;
/**
* Create a name resolver for the specified target, if possible. Throws an
* error if no such name resolver can be created.
* @param target
* @param listener
*/
function createResolver(target, listener) {

@@ -41,5 +60,26 @@ for (const prefix of Object.keys(registeredResolvers)) {

}
throw new Error('No resolver could be created for the provided target');
throw new Error(`No resolver could be created for target ${target}`);
}
exports.createResolver = createResolver;
/**
* Get the default authority for the specified target, if possible. Throws an
* error if no registered name resolver can parse that target string.
* @param target
*/
function getDefaultAuthority(target) {
for (const prefix of Object.keys(registerDefaultResolver)) {
if (target.startsWith(prefix)) {
return registeredResolvers[prefix].getDefaultAuthority(target);
}
}
if (defaultResolver !== null) {
return defaultResolver.getDefaultAuthority(target);
}
throw new Error(`Invalid target ${target}`);
}
exports.getDefaultAuthority = getDefaultAuthority;
function registerAll() {
resolver_dns.setup();
}
exports.registerAll = registerAll;
//# sourceMappingURL=resolver.js.map

@@ -5,6 +5,8 @@ /// <reference types="node" />

import { Duplex, Readable, Writable } from 'stream';
import { ServiceError } from './call';
import { StatusObject } from './call-stream';
import { Deserialize, Serialize } from './make-client';
import { Metadata } from './metadata';
import { ObjectReadable, ObjectWritable } from './object-stream';
export declare type ServerStatusResponse = Partial<StatusObject>;
export declare type ServerErrorResponse = ServerStatusResponse & Error;
export declare type ServerSurfaceCall = {

@@ -18,7 +20,7 @@ cancelled: boolean;

};
export declare type ServerReadableStream<RequestType, ResponseType> = ServerSurfaceCall & Readable;
export declare type ServerWritableStream<RequestType, ResponseType> = ServerSurfaceCall & Writable & {
export declare type ServerReadableStream<RequestType, ResponseType> = ServerSurfaceCall & ObjectReadable<RequestType>;
export declare type ServerWritableStream<RequestType, ResponseType> = ServerSurfaceCall & ObjectWritable<ResponseType> & {
request: RequestType | null;
};
export declare type ServerDuplexStream<RequestType, ResponseType> = ServerSurfaceCall & Duplex;
export declare type ServerDuplexStream<RequestType, ResponseType> = ServerSurfaceCall & ObjectReadable<RequestType> & ObjectWritable<ResponseType>;
export declare class ServerUnaryCallImpl<RequestType, ResponseType> extends EventEmitter implements ServerUnaryCall<RequestType, ResponseType> {

@@ -68,3 +70,3 @@ private call;

}
export declare type sendUnaryData<ResponseType> = (error: ServiceError | null, value: ResponseType | null, trailer?: Metadata, flags?: number) => void;
export declare type sendUnaryData<ResponseType> = (error: ServerErrorResponse | ServerStatusResponse | null, value: ResponseType | null, trailer?: Metadata, flags?: number) => void;
export declare type handleUnaryCall<RequestType, ResponseType> = (call: ServerUnaryCall<RequestType, ResponseType>, callback: sendUnaryData<ResponseType>) => void;

@@ -118,5 +120,5 @@ export declare type handleClientStreamingCall<RequestType, ResponseType> = (call: ServerReadableStream<RequestType, ResponseType>, callback: sendUnaryData<ResponseType>) => void;

deserializeMessage(bytes: Buffer): Promise<RequestType>;
sendUnaryMessage(err: ServiceError | null, value: ResponseType | null, metadata?: Metadata, flags?: number): Promise<void>;
sendUnaryMessage(err: ServerErrorResponse | ServerStatusResponse | null, value: ResponseType | null, metadata?: Metadata, flags?: number): Promise<void>;
sendStatus(statusObj: StatusObject): void;
sendError(error: ServiceError): void;
sendError(error: ServerErrorResponse | ServerStatusResponse): void;
write(chunk: Buffer): boolean | undefined;

@@ -123,0 +125,0 @@ resume(): void;

@@ -310,12 +310,12 @@ "use strict";

code: constants_1.Status.UNKNOWN,
details: error.hasOwnProperty('message')
details: ('message' in error)
? error.message
: 'Unknown Error',
metadata: error.hasOwnProperty('metadata')
metadata: ('metadata' in error && error.metadata !== undefined)
? error.metadata
: new metadata_1.Metadata(),
};
if (error.hasOwnProperty('code') && Number.isInteger(error.code)) {
if ('code' in error && typeof error.code === 'number' && Number.isInteger(error.code)) {
status.code = error.code;
if (error.hasOwnProperty('details')) {
if ('details' in error && typeof error.details === 'string') {
status.details = error.details;

@@ -322,0 +322,0 @@ }

import { Deserialize, Serialize, ServiceDefinition } from './make-client';
import { HandleCall } from './server-call';
import { ServerCredentials } from './server-credentials';
export declare type UntypedHandleCall = HandleCall<any, any>;
export interface UntypedServiceImplementation {
[name: string]: UntypedHandleCall;
}
export declare class Server {

@@ -11,3 +15,3 @@ private http2Server;

addProtoService(): void;
addService(service: ServiceDefinition, implementation: object): void;
addService(service: ServiceDefinition, implementation: UntypedServiceImplementation): void;
bind(port: string, creds: ServerCredentials): void;

@@ -14,0 +18,0 @@ bindAsync(port: string, creds: ServerCredentials, callback: (error: Error | null, port: number) => void): void;

@@ -69,3 +69,2 @@ "use strict";

}
const implMap = implementation;
serviceKeys.forEach(name => {

@@ -90,6 +89,6 @@ const attrs = service[name];

}
let implFn = implMap[name];
let implFn = implementation[name];
let impl;
if (implFn === undefined && typeof attrs.originalName === 'string') {
implFn = implMap[attrs.originalName];
implFn = implementation[attrs.originalName];
}

@@ -96,0 +95,0 @@ if (implFn !== undefined) {

@@ -30,3 +30,5 @@ import * as lbconfig from './load-balancing-config';

* @param percentage A number chosen from the range [0, 100) that is used to select which config to use
* @return The service configuration to use, given the percentage value, or null if the service config
* data has a valid format but none of the options match the current client.
*/
export declare function extractAndSelectServiceConfig(txtRecord: string[][], percentage: number): ServiceConfig | null;

@@ -21,17 +21,30 @@ "use strict";

* https://github.com/grpc/proposal/blob/master/A2-service-configs-in-dns.md
* https://github.com/grpc/grpc/blob/master/doc/service_config.md */
* https://github.com/grpc/grpc/blob/master/doc/service_config.md. Each
* function here takes an object with unknown structure and returns its
* specific object type if the input has the right structure, and throws an
* error otherwise. */
/* The any type is purposely used here. All functions validate their input at
* runtime */
/* tslint:disable:no-any */
const lbconfig = require("./load-balancing-config");
const util_1 = require("util");
const os = require("os");
/**
* Recognizes a number with up to 9 digits after the decimal point, followed by
* an "s", representing a number of seconds.
*/
const TIMEOUT_REGEX = /^\d+(\.\d{1,9})?s$/;
/**
* Client language name used for determining whether this client matches a
* `ServiceConfigCanaryConfig`'s `clientLanguage` list.
*/
const CLIENT_LANGUAGE_STRING = 'node';
function validateName(obj) {
if (!('service' in obj) || !util_1.isString(obj.service)) {
if (!('service' in obj) || typeof obj.service !== 'string') {
throw new Error('Invalid method config name: invalid service');
}
const result = {
service: obj.service
service: obj.service,
};
if ('method' in obj) {
if (util_1.isString(obj.method)) {
if (typeof obj.method === 'string') {
result.method = obj.method;

@@ -47,5 +60,5 @@ }

const result = {
name: []
name: [],
};
if (!('name' in obj) || !util_1.isArray(obj.name)) {
if (!('name' in obj) || !Array.isArray(obj.name)) {
throw new Error('Invalid method config: invalid name array');

@@ -57,3 +70,3 @@ }

if ('waitForReady' in obj) {
if (!util_1.isBoolean(obj.waitForReady)) {
if (typeof obj.waitForReady !== 'boolean') {
throw new Error('Invalid method config: invalid waitForReady');

@@ -64,3 +77,4 @@ }

if ('timeout' in obj) {
if (!util_1.isString(obj.timeout) || !TIMEOUT_REGEX.test(obj.timeout)) {
if (!(typeof obj.timeout === 'string') ||
!TIMEOUT_REGEX.test(obj.timeout)) {
throw new Error('Invalid method config: invalid timeout');

@@ -71,3 +85,3 @@ }

if ('maxRequestBytes' in obj) {
if (!util_1.isNumber(obj.maxRequestBytes)) {
if (typeof obj.maxRequestBytes !== 'number') {
throw new Error('Invalid method config: invalid maxRequestBytes');

@@ -78,3 +92,3 @@ }

if ('maxResponseBytes' in obj) {
if (!util_1.isNumber(obj.maxResponseBytes)) {
if (typeof obj.maxResponseBytes !== 'number') {
throw new Error('Invalid method config: invalid maxRequestBytes');

@@ -89,6 +103,6 @@ }

loadBalancingConfig: [],
methodConfig: []
methodConfig: [],
};
if ('loadBalancingPolicy' in obj) {
if (util_1.isString(obj.loadBalancingPolicy)) {
if (typeof obj.loadBalancingPolicy === 'string') {
result.loadBalancingPolicy = obj.loadBalancingPolicy;

@@ -101,3 +115,3 @@ }

if ('loadBalancingConfig' in obj) {
if (util_1.isArray(obj.loadBalancingConfig)) {
if (Array.isArray(obj.loadBalancingConfig)) {
for (const config of obj.loadBalancingConfig) {

@@ -112,3 +126,3 @@ result.loadBalancingConfig.push(lbconfig.validateConfig(config));

if ('methodConfig' in obj) {
if (util_1.isArray(obj.methodConfig)) {
if (Array.isArray(obj.methodConfig)) {
for (const methodConfig of obj.methodConfig) {

@@ -124,3 +138,4 @@ result.methodConfig.push(validateMethodConfig(methodConfig));

for (const seenName of seenMethodNames) {
if (name.service === seenName.service && name.method === seenName.method) {
if (name.service === seenName.service &&
name.method === seenName.method) {
throw new Error(`Invalid service config: duplicate name ${name.service}/${name.method}`);

@@ -139,9 +154,9 @@ }

const result = {
serviceConfig: validateServiceConfig(obj.serviceConfig)
serviceConfig: validateServiceConfig(obj.serviceConfig),
};
if ('clientLanguage' in obj) {
if (util_1.isArray(obj.clientLanguage)) {
if (Array.isArray(obj.clientLanguage)) {
result.clientLanguage = [];
for (const lang of obj.clientLanguage) {
if (util_1.isString(lang)) {
if (typeof lang === 'string') {
result.clientLanguage.push(lang);

@@ -159,6 +174,6 @@ }

if ('clientHostname' in obj) {
if (util_1.isArray(obj.clientHostname)) {
if (Array.isArray(obj.clientHostname)) {
result.clientHostname = [];
for (const lang of obj.clientHostname) {
if (util_1.isString(lang)) {
if (typeof lang === 'string') {
result.clientHostname.push(lang);

@@ -176,3 +191,5 @@ }

if ('percentage' in obj) {
if (util_1.isNumber(obj.percentage) && 0 <= obj.percentage && obj.percentage <= 100) {
if (typeof obj.percentage === 'number' &&
0 <= obj.percentage &&
obj.percentage <= 100) {
result.percentage = obj.percentage;

@@ -185,3 +202,8 @@ }

// Validate that no unexpected fields are present
const allowedFields = ['clientLanguage', 'percentage', 'clientHostname', 'serviceConfig'];
const allowedFields = [
'clientLanguage',
'percentage',
'clientHostname',
'serviceConfig',
];
for (const field in obj) {

@@ -195,3 +217,3 @@ if (!allowedFields.includes(field)) {

function validateAndSelectCanaryConfig(obj, percentage) {
if (!util_1.isArray(obj)) {
if (!Array.isArray(obj)) {
throw new Error('Invalid service config list');

@@ -203,6 +225,7 @@ }

* config if the field value does not match the current client */
if (util_1.isNumber(validatedConfig.percentage) && percentage > validatedConfig.percentage) {
if (typeof validatedConfig.percentage === 'number' &&
percentage > validatedConfig.percentage) {
continue;
}
if (util_1.isArray(validatedConfig.clientHostname)) {
if (Array.isArray(validatedConfig.clientHostname)) {
let hostnameMatched = false;

@@ -218,3 +241,3 @@ for (const hostname of validatedConfig.clientHostname) {

}
if (util_1.isArray(validatedConfig.clientLanguage)) {
if (Array.isArray(validatedConfig.clientLanguage)) {
let languageMatched = false;

@@ -240,2 +263,4 @@ for (const language of validatedConfig.clientLanguage) {

* @param percentage A number chosen from the range [0, 100) that is used to select which config to use
* @return The service configuration to use, given the percentage value, or null if the service config
* data has a valid format but none of the options match the current client.
*/

@@ -245,3 +270,5 @@ function extractAndSelectServiceConfig(txtRecord, percentage) {

if (record.length > 0 && record[0].startsWith('grpc_config=')) {
const recordString = [record[0].substring('grpc_config='.length)].concat(record.slice(1)).join('');
/* Treat the list of strings in this record as a single string and remove
* "grpc_config=" from the beginning. The rest should be a JSON string */
const recordString = record.join('').substring('grpc_config='.length);
const recordJson = JSON.parse(recordString);

@@ -248,0 +275,0 @@ return validateAndSelectCanaryConfig(recordJson, percentage);

{
"name": "@grpc/grpc-js",
"version": "0.5.2",
"version": "0.5.3",
"description": "gRPC Library for Node - pure JS implementation",

@@ -19,9 +19,21 @@ "homepage": "https://grpc.io/",

"@grpc/proto-loader": "^0.5.0",
"@types/gulp": "^4.0.6",
"@types/gulp-mocha": "0.0.32",
"@types/lodash": "^4.14.108",
"@types/mocha": "^5.2.6",
"@types/ncp": "^2.0.1",
"@types/node": "^12.0.2",
"@types/pify": "^3.0.2",
"@types/semver": "^6.0.1",
"clang-format": "^1.0.55",
"execa": "^2.0.3",
"gts": "^1.0.0",
"gulp": "^4.0.2",
"gulp-mocha": "^6.0.0",
"lodash": "^4.17.4",
"typescript": "~3.5.1"
"mocha-jenkins-reporter": "^0.4.1",
"ncp": "^2.0.0",
"pify": "^4.0.1",
"ts-node": "^8.3.0",
"typescript": "^3.5.3"
},

@@ -47,3 +59,3 @@ "contributors": [

"dependencies": {
"semver": "^6.0.0"
"semver": "^6.2.0"
},

@@ -50,0 +62,0 @@ "files": [

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc