fallback.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. "use strict";
  2. /**
  3. * Copyright 2020 Google LLC
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. Object.defineProperty(exports, "__esModule", { value: true });
  18. exports.fallback = exports.GoogleError = exports.operation = exports.Operation = exports.warn = exports.protobufMinimal = exports.protobuf = exports.LocationProtos = exports.IamProtos = exports.operationsProtos = exports.GrpcClient = exports.defaultToObjectOptions = exports.makeUUID = exports.LocationsClient = exports.IamClient = exports.OperationsClient = exports.StreamType = exports.StreamDescriptor = exports.PageDescriptor = exports.LongrunningDescriptor = exports.BundleDescriptor = exports.version = exports.createDefaultBackoffSettings = exports.RetryOptions = exports.constructSettings = exports.CallSettings = exports.routingHeader = exports.PathTemplate = void 0;
  19. exports.lro = lro;
  20. exports.createApiCall = createApiCall;
  21. const objectHash = require("object-hash");
  22. const protobuf = require("protobufjs");
  23. exports.protobuf = protobuf;
  24. const gax = require("./gax");
  25. const routingHeader = require("./routingHeader");
  26. exports.routingHeader = routingHeader;
  27. const status_1 = require("./status");
  28. const google_auth_library_1 = require("google-auth-library");
  29. const operationsClient_1 = require("./operationsClient");
  30. const createApiCall_1 = require("./createApiCall");
  31. const fallbackRest = require("./fallbackRest");
  32. const featureDetection_1 = require("./featureDetection");
  33. const fallbackServiceStub_1 = require("./fallbackServiceStub");
  34. const streaming_1 = require("./streamingCalls/streaming");
  35. const util_1 = require("./util");
  36. const IamProtos = require("../protos/iam_service");
  37. exports.IamProtos = IamProtos;
  38. const LocationProtos = require("../protos/locations");
  39. exports.LocationProtos = LocationProtos;
  40. const operationsProtos = require("../protos/operations");
  41. exports.operationsProtos = operationsProtos;
  42. var pathTemplate_1 = require("./pathTemplate");
  43. Object.defineProperty(exports, "PathTemplate", { enumerable: true, get: function () { return pathTemplate_1.PathTemplate; } });
  44. var gax_1 = require("./gax");
  45. Object.defineProperty(exports, "CallSettings", { enumerable: true, get: function () { return gax_1.CallSettings; } });
  46. Object.defineProperty(exports, "constructSettings", { enumerable: true, get: function () { return gax_1.constructSettings; } });
  47. Object.defineProperty(exports, "RetryOptions", { enumerable: true, get: function () { return gax_1.RetryOptions; } });
  48. Object.defineProperty(exports, "createDefaultBackoffSettings", { enumerable: true, get: function () { return gax_1.createDefaultBackoffSettings; } });
  49. exports.version = require('../../package.json').version + '-fallback';
  50. var descriptor_1 = require("./descriptor");
  51. Object.defineProperty(exports, "BundleDescriptor", { enumerable: true, get: function () { return descriptor_1.BundleDescriptor; } });
  52. Object.defineProperty(exports, "LongrunningDescriptor", { enumerable: true, get: function () { return descriptor_1.LongrunningDescriptor; } });
  53. Object.defineProperty(exports, "PageDescriptor", { enumerable: true, get: function () { return descriptor_1.PageDescriptor; } });
  54. Object.defineProperty(exports, "StreamDescriptor", { enumerable: true, get: function () { return descriptor_1.StreamDescriptor; } });
  55. var streaming_2 = require("./streamingCalls/streaming");
  56. Object.defineProperty(exports, "StreamType", { enumerable: true, get: function () { return streaming_2.StreamType; } });
  57. var operationsClient_2 = require("./operationsClient");
  58. Object.defineProperty(exports, "OperationsClient", { enumerable: true, get: function () { return operationsClient_2.OperationsClient; } });
  59. var iamService_1 = require("./iamService");
  60. Object.defineProperty(exports, "IamClient", { enumerable: true, get: function () { return iamService_1.IamClient; } });
  61. var locationService_1 = require("./locationService");
  62. Object.defineProperty(exports, "LocationsClient", { enumerable: true, get: function () { return locationService_1.LocationsClient; } });
  63. var util_2 = require("./util");
  64. Object.defineProperty(exports, "makeUUID", { enumerable: true, get: function () { return util_2.makeUUID; } });
  65. exports.defaultToObjectOptions = {
  66. keepCase: false,
  67. longs: String,
  68. enums: String,
  69. defaults: true,
  70. oneofs: true,
  71. };
  72. const CLIENT_VERSION_HEADER = 'x-goog-api-client';
  73. class GrpcClient {
  74. /**
  75. * In rare cases users might need to deallocate all memory consumed by loaded protos.
  76. * This method will delete the proto cache content.
  77. */
  78. static clearProtoCache() {
  79. GrpcClient.protoCache.clear();
  80. }
  81. /**
  82. * gRPC-fallback version of GrpcClient
  83. * Implements GrpcClient API for a browser using grpc-fallback protocol (sends serialized protobuf to HTTP/1 $rpc endpoint).
  84. *
  85. * @param {Object=} options.auth - An instance of OAuth2Client to use in browser, or an instance of GoogleAuth from google-auth-library
  86. * to use in Node.js. Required for browser, optional for Node.js.
  87. * @constructor
  88. */
  89. constructor(options = {}) {
  90. var _a;
  91. if (!(0, featureDetection_1.isNodeJS)()) {
  92. if (!options.auth) {
  93. throw new Error(JSON.stringify(options) +
  94. 'You need to pass auth instance to use gRPC-fallback client in browser or other non-Node.js environments. Use OAuth2Client from google-auth-library.');
  95. }
  96. this.auth = options.auth;
  97. }
  98. else {
  99. this.auth =
  100. options.auth ||
  101. new google_auth_library_1.GoogleAuth(options);
  102. }
  103. this.fallback = options.fallback ? true : false;
  104. this.grpcVersion = require('../../package.json').version;
  105. this.httpRules = options.httpRules;
  106. this.numericEnums = (_a = options.numericEnums) !== null && _a !== void 0 ? _a : false;
  107. }
  108. /**
  109. * gRPC-fallback version of loadProto
  110. * Loads the protobuf root object from a JSON object created from a proto file
  111. * @param {Object} jsonObject - A JSON version of a protofile created usin protobuf.js
  112. * @returns {Object} Root namespace of proto JSON
  113. */
  114. loadProto(jsonObject) {
  115. const rootObject = protobuf.Root.fromJSON(jsonObject);
  116. return rootObject;
  117. }
  118. loadProtoJSON(json, ignoreCache = false) {
  119. const hash = objectHash(JSON.stringify(json)).toString();
  120. const cached = GrpcClient.protoCache.get(hash);
  121. if (cached && !ignoreCache) {
  122. return cached;
  123. }
  124. const root = protobuf.Root.fromJSON(json);
  125. GrpcClient.protoCache.set(hash, root);
  126. return root;
  127. }
  128. static getServiceMethods(service) {
  129. const methods = {};
  130. for (const [methodName, methodObject] of Object.entries(service.methods)) {
  131. const methodNameLowerCamelCase = (0, util_1.toLowerCamelCase)(methodName);
  132. methods[methodNameLowerCamelCase] = methodObject;
  133. }
  134. return methods;
  135. }
  136. /**
  137. * gRPC-fallback version of constructSettings
  138. * A wrapper of {@link constructSettings} function under the gRPC context.
  139. *
  140. * Most of parameters are common among constructSettings, please take a look.
  141. * @param {string} serviceName - The fullly-qualified name of the service.
  142. * @param {Object} clientConfig - A dictionary of the client config.
  143. * @param {Object} configOverrides - A dictionary of overriding configs.
  144. * @param {Object} headers - A dictionary of additional HTTP header name to
  145. * its value.
  146. * @return {Object} A mapping of method names to CallSettings.
  147. */
  148. constructSettings(serviceName, clientConfig, configOverrides, headers) {
  149. function buildMetadata(abTests, moreHeaders) {
  150. const metadata = {};
  151. if (!headers) {
  152. headers = {};
  153. }
  154. // Since gRPC expects each header to be an array,
  155. // we are doing the same for fallback here.
  156. for (const key in headers) {
  157. metadata[key] = Array.isArray(headers[key])
  158. ? headers[key]
  159. : [headers[key]];
  160. }
  161. // gRPC-fallback request must have 'grpc-web/' in 'x-goog-api-client'
  162. const clientVersions = [];
  163. if (metadata[CLIENT_VERSION_HEADER] &&
  164. metadata[CLIENT_VERSION_HEADER][0]) {
  165. clientVersions.push(...metadata[CLIENT_VERSION_HEADER][0].split(' '));
  166. }
  167. clientVersions.push(`grpc-web/${exports.version}`);
  168. metadata[CLIENT_VERSION_HEADER] = [clientVersions.join(' ')];
  169. if (!moreHeaders) {
  170. return metadata;
  171. }
  172. for (const key in moreHeaders) {
  173. if (key.toLowerCase() !== CLIENT_VERSION_HEADER) {
  174. const value = moreHeaders[key];
  175. if (Array.isArray(value)) {
  176. if (metadata[key] === undefined) {
  177. metadata[key] = value;
  178. }
  179. else {
  180. if (Array.isArray(metadata[key])) {
  181. metadata[key].push(...value);
  182. }
  183. else {
  184. throw new Error(`Can not add value ${value} to the call metadata.`);
  185. }
  186. }
  187. }
  188. else {
  189. metadata[key] = [value];
  190. }
  191. }
  192. }
  193. return metadata;
  194. }
  195. return gax.constructSettings(serviceName, clientConfig, configOverrides, status_1.Status, { metadataBuilder: buildMetadata });
  196. }
  197. /**
  198. * gRPC-fallback version of createStub
  199. * Creates a gRPC-fallback stub with authentication headers built from supplied OAuth2Client instance
  200. *
  201. * @param {function} CreateStub - The constructor function of the stub.
  202. * @param {Object} service - A protobufjs Service object (as returned by lookupService)
  203. * @param {Object} opts - Connection options, as described below.
  204. * @param {string} opts.servicePath - The hostname of the API endpoint service.
  205. * @param {number} opts.port - The port of the service.
  206. * @return {Promise} A promise which resolves to a gRPC-fallback service stub, which is a protobuf.js service stub instance modified to match the gRPC stub API
  207. */
  208. async createStub(service, opts,
  209. // For consistency with createStub in grpc.ts, customServicePath is defined:
  210. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  211. customServicePath) {
  212. if (!this.authClient) {
  213. if (this.auth && 'getClient' in this.auth) {
  214. this.authClient = (await this.auth.getClient());
  215. }
  216. else if (this.auth && 'getRequestHeaders' in this.auth) {
  217. this.authClient = this.auth;
  218. }
  219. }
  220. if (!this.authClient) {
  221. throw new Error('No authentication was provided');
  222. }
  223. if (!opts.universeDomain) {
  224. opts.universeDomain = 'googleapis.com';
  225. }
  226. if (opts.universeDomain) {
  227. const universeFromAuth = this.authClient.universeDomain;
  228. if (universeFromAuth && opts.universeDomain !== universeFromAuth) {
  229. throw new Error(`The configured universe domain (${opts.universeDomain}) does not match the universe domain found in the credentials (${universeFromAuth}). ` +
  230. "If you haven't configured the universe domain explicitly, googleapis.com is the default.");
  231. }
  232. }
  233. service.resolveAll();
  234. const methods = GrpcClient.getServiceMethods(service);
  235. const protocol = opts.protocol || 'https';
  236. let servicePath = opts.servicePath;
  237. if (!servicePath &&
  238. service.options &&
  239. service.options['(google.api.default_host)']) {
  240. servicePath = service.options['(google.api.default_host)'];
  241. }
  242. if (!servicePath) {
  243. throw new Error(`Cannot determine service API path for service ${service.name}.`);
  244. }
  245. let servicePort;
  246. const match = servicePath.match(/^(.*):(\d+)$/);
  247. if (match) {
  248. servicePath = match[1];
  249. servicePort = parseInt(match[2]);
  250. }
  251. if (opts.port) {
  252. servicePort = opts.port;
  253. }
  254. else if (!servicePort) {
  255. servicePort = 443;
  256. }
  257. const encoder = fallbackRest.encodeRequest;
  258. const decoder = fallbackRest.decodeResponse;
  259. const serviceStub = (0, fallbackServiceStub_1.generateServiceStub)(methods, protocol, servicePath, servicePort, this.authClient, encoder, decoder, this.numericEnums);
  260. return serviceStub;
  261. }
  262. /**
  263. * Creates a 'bytelength' function for a given proto message class.
  264. *
  265. * See {@link BundleDescriptor} about the meaning of the return value.
  266. *
  267. * @param {function} message - a constructor function that is generated by
  268. * protobuf.js. Assumes 'encoder' field in the message.
  269. * @return {function(Object):number} - a function to compute the byte length
  270. * for an object.
  271. */
  272. static createByteLengthFunction(message) {
  273. return gax.createByteLengthFunction(message);
  274. }
  275. }
  276. exports.GrpcClient = GrpcClient;
  277. GrpcClient.protoCache = new Map();
  278. /**
  279. * gRPC-fallback version of lro
  280. *
  281. * @param {Object=} options.auth - An instance of google-auth-library.
  282. * @return {Object} A OperationsClientBuilder that will return a OperationsClient
  283. */
  284. function lro(options) {
  285. options = Object.assign({ scopes: [] }, options);
  286. if (options.protoJson) {
  287. options = Object.assign(options, { fallback: true });
  288. }
  289. const gaxGrpc = new GrpcClient(options);
  290. return new operationsClient_1.OperationsClientBuilder(gaxGrpc, options.protoJson);
  291. }
  292. /**
  293. * gRPC-fallback version of createApiCall
  294. *
  295. * Converts an rpc call into an API call governed by the settings.
  296. *
  297. * In typical usage, `func` will be a promise to a callable used to make an rpc
  298. * request. This will mostly likely be a bound method from a request stub used
  299. * to make an rpc call. It is not a direct function but a Promise instance,
  300. * because of its asynchronism (typically, obtaining the auth information).
  301. *
  302. * The result is a function which manages the API call with the given settings
  303. * and the options on the invocation.
  304. *
  305. * Throws exception on unsupported streaming calls
  306. *
  307. * @param {Promise<GRPCCall>|GRPCCall} func - is either a promise to be used to make
  308. * a bare RPC call, or just a bare RPC call.
  309. * @param {CallSettings} settings - provides the settings for this call
  310. * @param {Descriptor} descriptor - optionally specify the descriptor for
  311. * the method call.
  312. * @return {GaxCall} func - a bound method on a request stub used
  313. * to make an rpc call.
  314. */
  315. function createApiCall(func, settings, descriptor,
  316. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  317. _fallback // unused; for compatibility only
  318. ) {
  319. if (descriptor &&
  320. 'streaming' in descriptor &&
  321. descriptor.type !== streaming_1.StreamType.SERVER_STREAMING) {
  322. return () => {
  323. throw new Error('The REST transport currently does not support client-streaming or bidi-stream calls.');
  324. };
  325. }
  326. if (descriptor && 'streaming' in descriptor && !(0, featureDetection_1.isNodeJS)()) {
  327. return () => {
  328. throw new Error('Server streaming over the REST transport is only supported in Node.js.');
  329. };
  330. }
  331. return (0, createApiCall_1.createApiCall)(func, settings, descriptor);
  332. }
  333. exports.protobufMinimal = require("protobufjs/minimal");
  334. var warnings_1 = require("./warnings");
  335. Object.defineProperty(exports, "warn", { enumerable: true, get: function () { return warnings_1.warn; } });
  336. var longrunning_1 = require("./longRunningCalls/longrunning");
  337. Object.defineProperty(exports, "Operation", { enumerable: true, get: function () { return longrunning_1.Operation; } });
  338. Object.defineProperty(exports, "operation", { enumerable: true, get: function () { return longrunning_1.operation; } });
  339. var googleError_1 = require("./googleError");
  340. Object.defineProperty(exports, "GoogleError", { enumerable: true, get: function () { return googleError_1.GoogleError; } });
  341. // Different environments or bundlers may or may not respect "browser" field
  342. // in package.json (e.g. Electron does not respect it, but if you run the code
  343. // through webpack first, it will follow the "browser" field).
  344. // To make it safer and more compatible, let's make sure that if you do
  345. // const gax = require("google-gax");
  346. // you can always ask for gax.fallback, regardless of "browser" field being
  347. // understood or not.
  348. const fallback = module.exports;
  349. exports.fallback = fallback;
  350. //# sourceMappingURL=fallback.js.map