UNPKG

google-ads-node

Version:

Google Ads gRPC Client Library for Node

213 lines 17.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const grpc_1 = __importDefault(require("grpc")); const types_1 = require("./types"); const utils_1 = require("./utils"); const FAILURE_KEY = "google.ads.googleads.v2.errors.googleadsfailure-bin"; const REQUEST_ID_KEY = "request-id"; const RETRY_STATUS_CODES = [grpc_1.default.status.INTERNAL, grpc_1.default.status.RESOURCE_EXHAUSTED]; class MetadataInterceptor { constructor(developer_token, login_customer_id, access_token, auth) { this.developer_token = developer_token; this.login_customer_id = login_customer_id; this.access_token = access_token; this.auth = auth; this.requestInterceptor = this.buildRequester(); } intercept(options, nextCall) { return new grpc_1.default.InterceptingCall(nextCall(options), this.requestInterceptor); } buildRequester() { return new grpc_1.default.RequesterBuilder() .withStart(async (metadata, listener, next) => { const access_token = this.auth ? await this.auth.getAccessToken() : this.access_token; metadata.add(`Authorization`, `Bearer ${access_token}`); metadata.add(`developer-token`, this.developer_token); if (this.login_customer_id) { metadata.add(`login-customer-id`, this.login_customer_id); } next(metadata, listener); }) .build(); } } exports.MetadataInterceptor = MetadataInterceptor; class ExceptionInterceptor { constructor() { this.requestInterceptor = this.buildRequester(); } intercept(options, nextCall) { return new grpc_1.default.InterceptingCall(nextCall(options), this.requestInterceptor); } buildRequester() { return new grpc_1.default.RequesterBuilder() .withStart((metadata, _listener, next) => { const newListener = this.buildListener(); next(metadata, newListener); }) .build(); } buildListener() { return new grpc_1.default.ListenerBuilder() .withOnReceiveStatus((status, next) => { if (status.code !== grpc_1.default.status.OK) { // TODO: Throw this error instead of returning a new status? const error = this.handleGrpcFailure(status); if (error.hasOwnProperty("error_code")) { // @ts-ignore Custom error field "error_code" status.metadata.add("error-code", JSON.stringify(error.error_code)); } if (error.hasOwnProperty("location")) { // @ts-ignore Custom error field "location" status.metadata.add("location", error.location); } const errorStatus = new grpc_1.default.StatusBuilder() .withCode(status.code) .withDetails(error.message) .withMetadata(status.metadata) .build(); next(errorStatus); } else { next(status); } }) .build(); } getGoogleAdsFailure(metadata) { if (!metadata) { return null; } for (const key in metadata.getMap()) { if (key === FAILURE_KEY) { const message = metadata.get(key); try { const failure = types_1.GoogleAdsFailure.deserializeBinary(message[0]); return failure; } catch (err) { return null; } } } return null; } getRequestId(metadata) { if (metadata.get(REQUEST_ID_KEY)) { return metadata.get(REQUEST_ID_KEY)[0]; } return ""; } handleGrpcFailure(status) { const { code, metadata } = status; if (RETRY_STATUS_CODES.includes(code)) { /* Throw error if code one of INTERNAL or RESOURCE_EXHAUSTED */ return new Error(status.details); } const gaFailure = this.getGoogleAdsFailure(metadata); if (!gaFailure) { /* Throw error with status details if not a Google Ads API error */ return new Error(status.details); } const requestId = this.getRequestId(metadata); let error; const errorsList = gaFailure.getErrorsList(); if (errorsList && errorsList.length > 0) { const firstError = errorsList[0]; const firstErrorObj = firstError.toObject(); let path = ""; if (firstErrorObj.hasOwnProperty("location")) { path = utils_1.getErrorLocationPath(firstErrorObj.location); } return new ClientError(firstErrorObj.message, requestId, gaFailure, path); } try { /* Try to parse the error */ const errorPieces = gaFailure.toString().split(","); const errorMessage = errorPieces[errorPieces.length - 1]; error = new ClientError(errorMessage, requestId, gaFailure); } catch (err) { /* Use the original error message if parsing fails */ error = new ClientError(status.details, requestId, gaFailure); } return error; } } exports.ExceptionInterceptor = ExceptionInterceptor; class ResponseParsingInterceptor { constructor() { this.requestInterceptor = this.buildRequester(); } intercept(options, nextCall) { return new grpc_1.default.InterceptingCall(nextCall(options), this.requestInterceptor); } buildRequester() { return new grpc_1.default.RequesterBuilder() .withStart((metadata, _listener, next) => { const newListener = this.buildListener(); next(metadata, newListener); }) .build(); } buildListener() { return new grpc_1.default.ListenerBuilder() .withOnReceiveStatus((status, next) => { next(status); }) .withOnReceiveMessage((message, next) => { if (message && message.toObject) { let results = message.toObject(); if (results.partialFailureError && results.partialFailureError.detailsList) { const errors = []; const failure = types_1.GoogleAdsFailure.deserializeBinary(results .partialFailureError.detailsList[0].value); const errorsList = failure.getErrorsList(); for (const error of errorsList) { errors.push(error.toObject()); } results.partialFailureError.errors = utils_1.formatCallResults(errors, undefined); } const parsedResults = utils_1.formatCallResults( /* When retrieving a single entity via a service (e.g. CampaignService), the API returns a single object, instead of an array */ results.resultsList ? results.resultsList : [results], results.fieldMask); if (parsedResults && results.resultsList) { results.resultsList = parsedResults; } /* Return an object if it's a single entity via a service */ if (parsedResults && !results.resultsList) { results = parsedResults[0]; } next(results); } else { next(message); } }) .build(); } } exports.ResponseParsingInterceptor = ResponseParsingInterceptor; class ClientError extends Error { constructor(message, requestId, failure, path) { super(message); this.message = message; this.location = path || ""; this.request_id = requestId; this.failure = failure; if (failure.getErrorsList() && failure.getErrorsList().length > 0) { const errorCode = failure.getErrorsList()[0].getErrorCode(); this.error_code = errorCode.toObject(); } else { this.error_code = {}; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJjZXB0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL2ludGVyY2VwdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsZ0RBQXdCO0FBR3hCLG1DQUFzRTtBQUN0RSxtQ0FBa0U7QUFFbEUsTUFBTSxXQUFXLEdBQUcscURBQXFELENBQUM7QUFDMUUsTUFBTSxjQUFjLEdBQUcsWUFBWSxDQUFDO0FBQ3BDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxjQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxjQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUM7QUFLbEYsTUFBYSxtQkFBbUI7SUFPOUIsWUFDRSxlQUF1QixFQUN2QixpQkFBcUMsRUFDckMsWUFBZ0MsRUFDaEMsSUFBc0I7UUFFdEIsSUFBSSxDQUFDLGVBQWUsR0FBRyxlQUFlLENBQUM7UUFDdkMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLGlCQUFpQixDQUFDO1FBQzNDLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDbEQsQ0FBQztJQUVNLFNBQVMsQ0FBQyxPQUF5QixFQUFFLFFBQWtCO1FBQzVELE9BQU8sSUFBSSxjQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQy9FLENBQUM7SUFFTyxjQUFjO1FBQ3BCLE9BQU8sSUFBSSxjQUFJLENBQUMsZ0JBQWdCLEVBQUU7YUFDL0IsU0FBUyxDQUFDLEtBQUssRUFBRSxRQUF1QixFQUFFLFFBQXVCLEVBQUUsSUFBYyxFQUFFLEVBQUU7WUFDcEYsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMs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