@google-cloud/nodejs-common 2.0.3-alpha → 2.0.5-alpha
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/package.json +14 -14
- package/src/apis/dfa_reporting.js +18 -5
- package/src/apis/display_video.js +1 -1
- package/src/apis/doubleclick_search.js +3 -1
- package/src/apis/index.js +9 -1
- package/src/apis/search_ads.js +171 -0
- package/src/components/cloudfunctions_utils.js +0 -1
- package/src/components/storage.js +1 -2
- package/src/components/utils.js +31 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@google-cloud/nodejs-common",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5-alpha",
|
|
4
4
|
"description": "A NodeJs common library for solutions based on Cloud Functions",
|
|
5
5
|
"author": "Google Inc.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -16,23 +16,23 @@
|
|
|
16
16
|
},
|
|
17
17
|
"homepage": "https://github.com/GoogleCloudPlatform/cloud-for-marketing/blob/master/marketing-analytics/activation/common-libs/nodejs-common/README.md",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@google-cloud/aiplatform": "^3.
|
|
20
|
-
"@google-cloud/automl": "^4.0.
|
|
21
|
-
"@google-cloud/bigquery": "^7.
|
|
22
|
-
"@google-cloud/datastore": "^8.
|
|
23
|
-
"@google-cloud/firestore": "^
|
|
19
|
+
"@google-cloud/aiplatform": "^3.10.0",
|
|
20
|
+
"@google-cloud/automl": "^4.0.1",
|
|
21
|
+
"@google-cloud/bigquery": "^7.3.0",
|
|
22
|
+
"@google-cloud/datastore": "^8.4.0",
|
|
23
|
+
"@google-cloud/firestore": "^7.2.0",
|
|
24
24
|
"@google-cloud/logging-winston": "^6.0.0",
|
|
25
|
-
"@google-cloud/pubsub": "^4.
|
|
26
|
-
"@google-cloud/storage": "^7.0
|
|
27
|
-
"@google-cloud/scheduler": "^4.0.
|
|
28
|
-
"@google-cloud/secret-manager": "^5.0.
|
|
29
|
-
"gaxios": "^6.1.
|
|
25
|
+
"@google-cloud/pubsub": "^4.1.1",
|
|
26
|
+
"@google-cloud/storage": "^7.7.0",
|
|
27
|
+
"@google-cloud/scheduler": "^4.0.1",
|
|
28
|
+
"@google-cloud/secret-manager": "^5.0.1",
|
|
29
|
+
"gaxios": "^6.1.1",
|
|
30
30
|
"google-ads-api": "^14.1.0",
|
|
31
31
|
"google-ads-node": "^12.0.2",
|
|
32
|
-
"google-auth-library": "^9.
|
|
33
|
-
"googleapis": "^
|
|
32
|
+
"google-auth-library": "^9.4.2",
|
|
33
|
+
"googleapis": "^131.0.0",
|
|
34
34
|
"winston": "^3.10.0",
|
|
35
|
-
"@grpc/grpc-js": "1.9.
|
|
35
|
+
"@grpc/grpc-js": "1.9.14",
|
|
36
36
|
"lodash": "^4.17.21"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
@@ -41,12 +41,16 @@ const API_VERSION = 'v4';
|
|
|
41
41
|
* profileId, idType, conversion, customVariables, encryptionInfo.
|
|
42
42
|
* The 'idType' can be one of the values: 'encryptedUserId', 'gclid' or
|
|
43
43
|
* 'mobileDeviceId'.
|
|
44
|
+
* The 'operation' can be 'insert' or 'update'. The default value is 'insert'.
|
|
45
|
+
* 'insert' stands for https://developers.google.com/doubleclick-advertisers/rest/v4/conversions/batchinsert
|
|
46
|
+
* 'update' stands for https://developers.google.com/doubleclick-advertisers/rest/v4/conversions/batchupdate
|
|
44
47
|
* For other properties, see
|
|
45
48
|
* https://developers.google.com/doubleclick-advertisers/guides/conversions_update
|
|
46
49
|
*
|
|
47
50
|
* @typedef {{
|
|
48
51
|
* profileId:string,
|
|
49
52
|
* idType:string,
|
|
53
|
+
* operation:'insert'|'update'|undefined,
|
|
50
54
|
* conversion:{
|
|
51
55
|
* floodlightConfigurationId:string,
|
|
52
56
|
* floodlightActivityId:string,
|
|
@@ -60,7 +64,7 @@ const API_VERSION = 'v4';
|
|
|
60
64
|
* }|undefined),
|
|
61
65
|
* }}
|
|
62
66
|
*/
|
|
63
|
-
let
|
|
67
|
+
let ConversionsConfig;
|
|
64
68
|
|
|
65
69
|
/**
|
|
66
70
|
* List of properties that will be take from the data file as elements of a
|
|
@@ -155,7 +159,7 @@ class DfaReporting {
|
|
|
155
159
|
/**
|
|
156
160
|
* Returns the function to sends out a request to CM with a batch of
|
|
157
161
|
* conversions.
|
|
158
|
-
* @param {!
|
|
162
|
+
* @param {!ConversionsConfig} config Campaign Manager configuration.
|
|
159
163
|
* @return {!SendSingleBatch} Function which can send a batch of hits to
|
|
160
164
|
* Campaign Manager.
|
|
161
165
|
*/
|
|
@@ -171,6 +175,15 @@ class DfaReporting {
|
|
|
171
175
|
/** @type {function} Gets the conversion elements from the data object. */
|
|
172
176
|
const filterObject = getFilterFunction(PICKED_PROPERTIES);
|
|
173
177
|
const time = new Date().getTime();
|
|
178
|
+
const operation =
|
|
179
|
+
config.operation === 'update' ? 'batchupdate' : 'batchinsert';
|
|
180
|
+
// customVariables is not supported by batchupdate.
|
|
181
|
+
// https://developers.google.com/doubleclick-advertisers/rest/v4/Conversion#CustomFloodlightVariable
|
|
182
|
+
if (operation === 'batchupdate' &&
|
|
183
|
+
typeof config.customVariables !== 'undefined') {
|
|
184
|
+
this.logger.warn('customVariables is not supported by batchupdate');
|
|
185
|
+
delete config.customVariables;
|
|
186
|
+
}
|
|
174
187
|
const conversions = lines.map((line) => {
|
|
175
188
|
const record = JSON.parse(line);
|
|
176
189
|
const conversion = Object.assign(
|
|
@@ -184,7 +197,7 @@ class DfaReporting {
|
|
|
184
197
|
// Custom Variables
|
|
185
198
|
if (typeof config.customVariables !== 'undefined') {
|
|
186
199
|
conversion.customVariables = config.customVariables.map(
|
|
187
|
-
|
|
200
|
+
(variable) => ({ 'type': variable, 'value': record[variable], }));
|
|
188
201
|
}
|
|
189
202
|
// User Identifiers
|
|
190
203
|
if (record.userIdentifiers) {
|
|
@@ -225,7 +238,7 @@ class DfaReporting {
|
|
|
225
238
|
};
|
|
226
239
|
try {
|
|
227
240
|
const dfareporting = await this.getApiClient_();
|
|
228
|
-
const response = await dfareporting.conversions
|
|
241
|
+
const response = await dfareporting.conversions[operation]({
|
|
229
242
|
profileId: config.profileId,
|
|
230
243
|
requestBody: requestBody,
|
|
231
244
|
});
|
|
@@ -411,7 +424,7 @@ class DfaReporting {
|
|
|
411
424
|
|
|
412
425
|
module.exports = {
|
|
413
426
|
DfaReporting,
|
|
414
|
-
|
|
427
|
+
ConversionsConfig,
|
|
415
428
|
API_VERSION,
|
|
416
429
|
API_SCOPES,
|
|
417
430
|
};
|
|
@@ -370,7 +370,9 @@ class DoubleClickSearch {
|
|
|
370
370
|
const doubleclicksearch = await this.getApiClient_();
|
|
371
371
|
const response = await doubleclicksearch.reports.getFile(
|
|
372
372
|
{reportId, reportFragment});
|
|
373
|
-
if (response.status === 200)
|
|
373
|
+
if (response.status === 200) {
|
|
374
|
+
return Buffer.from(await response.data.arrayBuffer()).toString();
|
|
375
|
+
}
|
|
374
376
|
const errorMsg =
|
|
375
377
|
`Error in get file from reports: ${reportFragment}@${reportId}`;
|
|
376
378
|
this.logger.error(errorMsg, response);
|
package/src/apis/index.js
CHANGED
|
@@ -25,7 +25,7 @@ exports.AuthClient = require('./auth_client.js');
|
|
|
25
25
|
* APIs integration class for DFA Reporting API.
|
|
26
26
|
* @const {{
|
|
27
27
|
* DfaReporting:!DfaReporting,
|
|
28
|
-
*
|
|
28
|
+
* ConversionsConfig:!ConversionsConfig,
|
|
29
29
|
* }}
|
|
30
30
|
*/
|
|
31
31
|
exports.dfareporting = require('./dfa_reporting.js');
|
|
@@ -77,6 +77,14 @@ exports.spreadsheets = require('./spreadsheets.js');
|
|
|
77
77
|
*/
|
|
78
78
|
exports.doubleclicksearch = require('./doubleclick_search.js');
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* APIs integration class for Search Ads 360 Reporting.
|
|
82
|
+
* @const {{
|
|
83
|
+
* SearchAds:!SearchAds,
|
|
84
|
+
* }}
|
|
85
|
+
*/
|
|
86
|
+
exports.searchads = require('./search_ads.js');
|
|
87
|
+
|
|
80
88
|
/**
|
|
81
89
|
* APIs integration class for DoubleClick BidManager (DV360).
|
|
82
90
|
* @const {{
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// Copyright 2019 Google Inc.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @fileoverview Google Search Ads 360 Reporting on GoogleAPI Client Library.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
const { google } = require('googleapis');
|
|
22
|
+
const AuthClient = require('./auth_client.js');
|
|
23
|
+
const { getLogger } = require('../components/utils.js');
|
|
24
|
+
|
|
25
|
+
const API_SCOPES = Object.freeze([
|
|
26
|
+
'https://www.googleapis.com/auth/doubleclicksearch',
|
|
27
|
+
]);
|
|
28
|
+
const API_VERSION = 'v0';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Search Ads 360 Reporting API stub.
|
|
32
|
+
* See: https://developers.google.com/search-ads/reporting/api/reference/release-notes
|
|
33
|
+
*/
|
|
34
|
+
class SearchAds {
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @constructor
|
|
38
|
+
* @param {!Object<string,string>=} env The environment object to hold env
|
|
39
|
+
* variables.
|
|
40
|
+
*/
|
|
41
|
+
constructor(env = process.env) {
|
|
42
|
+
this.authClient = new AuthClient(API_SCOPES, env);
|
|
43
|
+
this.logger = getLogger('API.SA');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Prepares the Search Ads 360 Reporting API instance.
|
|
48
|
+
* OAuth 2.0 application credentials is required for calling this API.
|
|
49
|
+
* For Search Ads Reporting API calls made by a manager to a client account,
|
|
50
|
+
* a HTTP header named `login-customer-id` is required in the request. This
|
|
51
|
+
* value represents the Search Ads 360 customer ID of the manager making the
|
|
52
|
+
* API call. Be sure to remove any hyphens (—), for example: 1234567890, not
|
|
53
|
+
* 123-456-7890.
|
|
54
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/auth
|
|
55
|
+
* @return {!google.searchads360}
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
async getApiClient_(loginCustomerId) {
|
|
59
|
+
this.logger.debug(`Initialized Search Ads reporting instance for ${loginCustomerId}`);
|
|
60
|
+
this.searchads360 = google.searchads360({
|
|
61
|
+
version: API_VERSION,
|
|
62
|
+
auth: await this.getAuth_(),
|
|
63
|
+
headers: { 'login-customer-id': loginCustomerId },
|
|
64
|
+
});
|
|
65
|
+
return this.searchads360;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Gets the auth object.
|
|
70
|
+
* @return {!Promise<{!OAuth2Client|!JWT|!Compute}>}
|
|
71
|
+
*/
|
|
72
|
+
async getAuth_() {
|
|
73
|
+
if (this.auth) return this.auth;
|
|
74
|
+
await this.authClient.prepareCredentials();
|
|
75
|
+
this.auth = this.authClient.getDefaultAuth();
|
|
76
|
+
return this.auth;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Returns all rows that match the search stream query.
|
|
81
|
+
* The streamed content is not NDJSON format, but one JSON object with the
|
|
82
|
+
* property `results`. The whole JSON string can be parsed to an object and
|
|
83
|
+
* the `results` be extracted and converted to NDJSON lines. If the report
|
|
84
|
+
* is too large to be handled in this way, a possible solution is to parse
|
|
85
|
+
* the string directly to get the content of `results`.
|
|
86
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/customers.searchAds360/searchStream
|
|
87
|
+
* @param {string} customerId
|
|
88
|
+
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
89
|
+
* @param {string} query
|
|
90
|
+
* @return {!ReadableStream}
|
|
91
|
+
*/
|
|
92
|
+
async streamReport(customerId, loginCustomerId, query) {
|
|
93
|
+
const searchads = await this.getApiClient_(loginCustomerId);
|
|
94
|
+
const response = await searchads.customers.searchAds360.search({
|
|
95
|
+
customerId,
|
|
96
|
+
requestBody: { query },
|
|
97
|
+
}, { responseType: 'stream' });
|
|
98
|
+
return response.data;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Gets a report synchronously from a given Customer account.
|
|
103
|
+
* This is for test as it does not handle page token. For product env, use
|
|
104
|
+
* function `streamReport`.
|
|
105
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/customers.searchAds360/search#request-body
|
|
106
|
+
* @param {string} customerId
|
|
107
|
+
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
108
|
+
* @param {string} query
|
|
109
|
+
* @return {!SearchAds360Field}
|
|
110
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/searchAds360Fields#SearchAds360Field
|
|
111
|
+
*/
|
|
112
|
+
async getReport(customerId, loginCustomerId, query) {
|
|
113
|
+
const searchads = await this.getApiClient_(loginCustomerId);
|
|
114
|
+
const response = await searchads.customers.searchAds360.search({
|
|
115
|
+
customerId,
|
|
116
|
+
requestBody: { query },
|
|
117
|
+
});
|
|
118
|
+
return response.data.results;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Returns the requested field or resource (artifact) used by SearchAds360Service.
|
|
123
|
+
* This service doesn't require `login-customer-id` HTTP header.
|
|
124
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/searchAds360Fields/get
|
|
125
|
+
* @param {string} resourceName
|
|
126
|
+
* @return {!SearchAds360Field}
|
|
127
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/searchAds360Fields#SearchAds360Field
|
|
128
|
+
*/
|
|
129
|
+
async getReportField(resourceName) {
|
|
130
|
+
const searchads = await this.getApiClient_();
|
|
131
|
+
const response = await searchads.searchAds360Fields.get({ resourceName });
|
|
132
|
+
return response.data;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Returns all the custom columns associated with the customer in full detail.
|
|
137
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/customers.customColumns/list
|
|
138
|
+
* @param {string} customerId - The ID of the customer.
|
|
139
|
+
* @param {string} loginCustomerId - The ID of the manager.
|
|
140
|
+
* @return {!Array<CustomColumn>}
|
|
141
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/customers.customColumns#CustomColumn
|
|
142
|
+
*/
|
|
143
|
+
async listCustomColumns(customerId, loginCustomerId) {
|
|
144
|
+
const searchads = await this.getApiClient_(loginCustomerId);
|
|
145
|
+
const response = await searchads.customers.customColumns.list({ customerId });
|
|
146
|
+
return response.data.customColumns;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Returns the requested custom column in full detail.
|
|
151
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/customers.customColumns/get
|
|
152
|
+
* @param {string} columnId - The ID of the customColumn.
|
|
153
|
+
* @param {string} customerId - The ID of the customer.
|
|
154
|
+
* @param {string} loginCustomerId - The ID of the manager.
|
|
155
|
+
* @return {!CustomColumn}
|
|
156
|
+
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/customers.customColumns#CustomColumn
|
|
157
|
+
*/
|
|
158
|
+
async getCustomColumn(columnId, customerId, loginCustomerId) {
|
|
159
|
+
const resourceName = `customers/${customerId}/customColumns/${columnId}`;
|
|
160
|
+
const searchads = await this.getApiClient_(loginCustomerId);
|
|
161
|
+
const response = await searchads.customers.customColumns.get({ resourceName });
|
|
162
|
+
return response.data;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = {
|
|
168
|
+
SearchAds,
|
|
169
|
+
API_VERSION,
|
|
170
|
+
API_SCOPES,
|
|
171
|
+
};
|
|
@@ -179,7 +179,7 @@ class StorageFile {
|
|
|
179
179
|
.on('finish', async () => {
|
|
180
180
|
const [{ contentType }] = await this.file.getMetadata();
|
|
181
181
|
const [file] = await outputFile.setMetadata({ contentType });
|
|
182
|
-
|
|
182
|
+
resolve(file.name);
|
|
183
183
|
});
|
|
184
184
|
});
|
|
185
185
|
}
|
|
@@ -255,4 +255,3 @@ module.exports = {
|
|
|
255
255
|
LINE_BREAKER,
|
|
256
256
|
DEFAULT_SPLIT_SIZE,
|
|
257
257
|
};
|
|
258
|
-
|
package/src/components/utils.js
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
const winston = require('winston');
|
|
22
22
|
const {inspect} = require('util');
|
|
23
23
|
const { LoggingWinston } = require('@google-cloud/logging-winston');
|
|
24
|
+
const { request } = require('gaxios');
|
|
25
|
+
const lodash = require('lodash');
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* The result of a batch of data sent to target API. The batch here means the
|
|
@@ -537,6 +539,34 @@ const changeNamingFromSnakeToLowerCamel = (name) => {
|
|
|
537
539
|
(initial) => initial.substring(1).toUpperCase());
|
|
538
540
|
};
|
|
539
541
|
|
|
542
|
+
/**
|
|
543
|
+
* Returns the response data for a HTTP request. It will retry the specific
|
|
544
|
+
* times if there was errors happened.
|
|
545
|
+
* @param {object} options Options for the request.
|
|
546
|
+
* @param {object=} logger Default is `console`.
|
|
547
|
+
* @param {number=} retryTimes Default value 3.
|
|
548
|
+
* @return {object}
|
|
549
|
+
*/
|
|
550
|
+
const requestWithRetry = async (options, logger = console, retryTimes = 3) => {
|
|
551
|
+
let processedTimes = 0;
|
|
552
|
+
do {
|
|
553
|
+
// Wait sometime (2s, 4s, 8s, ...) before each retry.
|
|
554
|
+
if (processedTimes > 0) await wait(2 ** processedTimes * 1000);
|
|
555
|
+
try {
|
|
556
|
+
const requestOption = lodash.merge({
|
|
557
|
+
responseType: 'json',
|
|
558
|
+
method: 'POST',
|
|
559
|
+
}, options);
|
|
560
|
+
const response = await request(requestOption);
|
|
561
|
+
return response.data;
|
|
562
|
+
} catch (error) {
|
|
563
|
+
processedTimes++;
|
|
564
|
+
if (processedTimes > retryTimes) throw error;
|
|
565
|
+
logger.error(`Request ${JSON.stringify(options)}`, error);
|
|
566
|
+
}
|
|
567
|
+
} while (processedTimes <= retryTimes)
|
|
568
|
+
}
|
|
569
|
+
|
|
540
570
|
// noinspection JSUnusedAssignment
|
|
541
571
|
module.exports = {
|
|
542
572
|
getLogger,
|
|
@@ -554,4 +584,5 @@ module.exports = {
|
|
|
554
584
|
getObjectByPath,
|
|
555
585
|
changeNamingFromSnakeToUpperCamel,
|
|
556
586
|
changeNamingFromSnakeToLowerCamel,
|
|
587
|
+
requestWithRetry,
|
|
557
588
|
};
|