@google-cloud/nodejs-common 2.0.16-beta → 2.1.1
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/README.md +4 -3
- package/bin/google_ads.sh +1 -1
- package/bin/install_functions.sh +1 -0
- package/package.json +1 -1
- package/src/apis/analytics.js +17 -21
- package/src/apis/base/ads_api_common.js +99 -0
- package/src/apis/base/google_api_client.js +55 -0
- package/src/apis/dfa_reporting.js +17 -33
- package/src/apis/display_video.js +13 -44
- package/src/apis/doubleclick_bidmanager.js +34 -42
- package/src/apis/doubleclick_search.js +17 -33
- package/src/apis/google_ads_api.js +94 -45
- package/src/apis/index.js +0 -1
- package/src/apis/search_ads.js +114 -52
- package/src/apis/spreadsheets.js +16 -23
- package/src/apis/youtube.js +18 -26
- package/src/components/firestore/datastore_mode_access.js +4 -3
- package/src/components/utils.js +23 -5
|
@@ -19,9 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
'use strict';
|
|
21
21
|
|
|
22
|
-
const {google} = require('googleapis');
|
|
23
22
|
const {request} = require('gaxios');
|
|
24
|
-
const
|
|
23
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
25
24
|
const {
|
|
26
25
|
getLogger,
|
|
27
26
|
SendSingleBatch,
|
|
@@ -118,7 +117,7 @@ let ReportRequest;
|
|
|
118
117
|
* Quota limits, see:
|
|
119
118
|
* https://support.google.com/adsihc/answer/6346075?hl=en
|
|
120
119
|
*/
|
|
121
|
-
class DoubleClickSearch {
|
|
120
|
+
class DoubleClickSearch extends GoogleApiClient {
|
|
122
121
|
|
|
123
122
|
/**
|
|
124
123
|
* @constructor
|
|
@@ -126,34 +125,19 @@ class DoubleClickSearch {
|
|
|
126
125
|
* variables.
|
|
127
126
|
*/
|
|
128
127
|
constructor(env = process.env) {
|
|
129
|
-
|
|
128
|
+
super(env);
|
|
129
|
+
this.googleApi = 'doubleclicksearch';
|
|
130
130
|
this.logger = getLogger('API.DS');
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
/**
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
* @private
|
|
137
|
-
*/
|
|
138
|
-
async getApiClient_() {
|
|
139
|
-
if (this.doubleclicksearch) return this.doubleclicksearch;
|
|
140
|
-
this.logger.debug(`Initialized ${this.constructor.name} instance.`);
|
|
141
|
-
this.doubleclicksearch = google.doubleclicksearch({
|
|
142
|
-
version: API_VERSION,
|
|
143
|
-
auth: await this.getAuth_(),
|
|
144
|
-
});
|
|
145
|
-
return this.doubleclicksearch;
|
|
133
|
+
/** @override */
|
|
134
|
+
getScope() {
|
|
135
|
+
return API_SCOPES;
|
|
146
136
|
}
|
|
147
137
|
|
|
148
|
-
/**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
*/
|
|
152
|
-
async getAuth_() {
|
|
153
|
-
if (this.auth) return this.auth;
|
|
154
|
-
await this.authClient.prepareCredentials();
|
|
155
|
-
this.auth = this.authClient.getDefaultAuth();
|
|
156
|
-
return this.auth;
|
|
138
|
+
/** @override */
|
|
139
|
+
getVersion() {
|
|
140
|
+
return API_VERSION;
|
|
157
141
|
}
|
|
158
142
|
|
|
159
143
|
/**
|
|
@@ -172,7 +156,7 @@ class DoubleClickSearch {
|
|
|
172
156
|
});
|
|
173
157
|
this.logger.debug('Sending out availabilities', availabilities);
|
|
174
158
|
try {
|
|
175
|
-
const doubleclicksearch = await this.
|
|
159
|
+
const doubleclicksearch = await this.getApiClient();
|
|
176
160
|
const response = await doubleclicksearch.conversion.updateAvailability(
|
|
177
161
|
{requestBody: {availabilities}});
|
|
178
162
|
this.logger.debug('Get response: ', response);
|
|
@@ -221,7 +205,7 @@ class DoubleClickSearch {
|
|
|
221
205
|
numberOfLines: lines.length,
|
|
222
206
|
};
|
|
223
207
|
try {
|
|
224
|
-
const doubleclicksearch = await this.
|
|
208
|
+
const doubleclicksearch = await this.getApiClient();
|
|
225
209
|
const response = await doubleclicksearch.conversion.insert(
|
|
226
210
|
{requestBody: {conversion: conversions}}
|
|
227
211
|
);
|
|
@@ -322,7 +306,7 @@ class DoubleClickSearch {
|
|
|
322
306
|
* @return {!Promise<string>}
|
|
323
307
|
*/
|
|
324
308
|
async requestReports(requestBody) {
|
|
325
|
-
const doubleclicksearch = await this.
|
|
309
|
+
const doubleclicksearch = await this.getApiClient();
|
|
326
310
|
const { status, data } = await doubleclicksearch.reports.request({ requestBody });
|
|
327
311
|
if (status >= 200 && status < 300) {
|
|
328
312
|
return data.id;
|
|
@@ -341,7 +325,7 @@ class DoubleClickSearch {
|
|
|
341
325
|
* }>>}
|
|
342
326
|
*/
|
|
343
327
|
async getReportUrls(reportId) {
|
|
344
|
-
const doubleclicksearch = await this.
|
|
328
|
+
const doubleclicksearch = await this.getApiClient();
|
|
345
329
|
const { status, data } = await doubleclicksearch.reports.get({ reportId });
|
|
346
330
|
switch (status) {
|
|
347
331
|
case 200:
|
|
@@ -367,11 +351,11 @@ class DoubleClickSearch {
|
|
|
367
351
|
* @return {!Promise<string>}
|
|
368
352
|
*/
|
|
369
353
|
async getReportFile(reportId, reportFragment) {
|
|
370
|
-
const doubleclicksearch = await this.
|
|
354
|
+
const doubleclicksearch = await this.getApiClient();
|
|
371
355
|
const response = await doubleclicksearch.reports.getFile(
|
|
372
356
|
{reportId, reportFragment});
|
|
373
357
|
if (response.status === 200) {
|
|
374
|
-
return
|
|
358
|
+
return response.data;
|
|
375
359
|
}
|
|
376
360
|
const errorMsg =
|
|
377
361
|
`Error in get file from reports: ${reportFragment}@${reportId}`;
|
|
@@ -387,7 +371,7 @@ class DoubleClickSearch {
|
|
|
387
371
|
* @return {!Promise<ReadableStream>}
|
|
388
372
|
*/
|
|
389
373
|
async getReportFileStream(url) {
|
|
390
|
-
const auth = await this.
|
|
374
|
+
const auth = await this.getAuth();
|
|
391
375
|
const headers = await auth.getRequestHeaders();
|
|
392
376
|
const response = await request({
|
|
393
377
|
method: 'GET',
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
const { Transform } = require('stream');
|
|
24
24
|
const lodash = require('lodash');
|
|
25
|
-
|
|
25
|
+
const { request: gaxiosRequest } = require('gaxios');
|
|
26
26
|
const {
|
|
27
27
|
ConversionAdjustmentUploadServiceClient,
|
|
28
28
|
ConversionUploadServiceClient,
|
|
@@ -33,6 +33,8 @@ const {
|
|
|
33
33
|
UserListServiceClient,
|
|
34
34
|
protos: { google: { ads: { googleads } } },
|
|
35
35
|
} = require('google-ads-nodejs-client');
|
|
36
|
+
|
|
37
|
+
const API_VERSION = Object.keys(googleads)[0];
|
|
36
38
|
const {
|
|
37
39
|
common: {
|
|
38
40
|
Consent,
|
|
@@ -88,7 +90,7 @@ const {
|
|
|
88
90
|
UserListTypeEnum: { UserListType },
|
|
89
91
|
CustomerMatchUploadKeyTypeEnum: { CustomerMatchUploadKeyType },
|
|
90
92
|
},
|
|
91
|
-
} = googleads
|
|
93
|
+
} = googleads[API_VERSION];
|
|
92
94
|
|
|
93
95
|
const AuthClient = require('./auth_client.js');
|
|
94
96
|
const {
|
|
@@ -99,10 +101,12 @@ const {
|
|
|
99
101
|
changeObjectNamingFromSnakeToLowerCamel,
|
|
100
102
|
changeObjectNamingFromLowerCamelToSnake,
|
|
101
103
|
} = require('../components/utils.js');
|
|
104
|
+
const { getCleanCid, RestSearchStreamTransform }
|
|
105
|
+
= require('./base/ads_api_common.js');
|
|
102
106
|
|
|
103
107
|
/** @type {!ReadonlyArray<string>} */
|
|
104
108
|
const API_SCOPES = Object.freeze(['https://www.googleapis.com/auth/adwords']);
|
|
105
|
-
|
|
109
|
+
const API_ENDPOINT = 'https://googleads.googleapis.com';
|
|
106
110
|
/**
|
|
107
111
|
* List of properties that will be taken from the data file as elements of a
|
|
108
112
|
* conversion or a conversion adjustment.
|
|
@@ -257,6 +261,9 @@ let ConversionConfig;
|
|
|
257
261
|
* If audience listId is not present, 'listName' and 'uploadKeyType' need to
|
|
258
262
|
* be there so they can be used to create a customer match user list.
|
|
259
263
|
* operation must be one of 'create' or 'remove'.
|
|
264
|
+
* `customerMatchUserListMetadata` offers a request level metadata, including
|
|
265
|
+
* 'consent'. While the top level 'consent', if presents, it will serve as the
|
|
266
|
+
* fallback value for each UserIdentifier.
|
|
260
267
|
* Should not include `userIdentifierSource` based on:
|
|
261
268
|
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier
|
|
262
269
|
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserDataOperation
|
|
@@ -267,6 +274,7 @@ let ConversionConfig;
|
|
|
267
274
|
* listId: (string|undefined),
|
|
268
275
|
* listName: (string|undefined),
|
|
269
276
|
* uploadKeyType: ('CONTACT_INFO'|'CRM_ID'|'MOBILE_ADVERTISING_ID'|undefined),
|
|
277
|
+
* customerMatchUserListMetadata: (undefined|CustomerMatchUserListMetadata),
|
|
270
278
|
* operation: ('create'|'remove'),
|
|
271
279
|
* consent: (!Consent),
|
|
272
280
|
* }}
|
|
@@ -284,6 +292,9 @@ let CustomerMatchConfig;
|
|
|
284
292
|
* create a customer match user list.
|
|
285
293
|
* For job type 'CUSTOMER_MATCH_WITH_ATTRIBUTES', 'user_attribute' can be used
|
|
286
294
|
* to store shared additional user attributes.
|
|
295
|
+
* For job type 'CUSTOMER_MATCH_*', `customerMatchUserListMetadata` offers a job
|
|
296
|
+
* level metadata, including 'consent'. While the top level 'consent',
|
|
297
|
+
* if presents, it will serve as the fallback value for each UserIdentifier.
|
|
287
298
|
* For job type 'STORE_SALES_UPLOAD_FIRST_PARTY', `storeSalesMetadata` is
|
|
288
299
|
* required to offer StoreSalesMetadata. Besides that, for the store sales data,
|
|
289
300
|
* common data (e.g. `currencyCode`, `conversionAction`) in
|
|
@@ -298,6 +309,7 @@ let CustomerMatchConfig;
|
|
|
298
309
|
* operation: ('create'|'remove'),
|
|
299
310
|
* type: !OfflineUserDataJobType,
|
|
300
311
|
* storeSalesMetadata: (undefined|StoreSalesMetadata),
|
|
312
|
+
* customerMatchUserListMetadata: (undefined|CustomerMatchUserListMetadata),
|
|
301
313
|
* transactionAttribute: (undefined|TransactionAttribute),
|
|
302
314
|
* userAttribute: (undefined|UserAttribute),
|
|
303
315
|
* userIdentifierSource: (!UserIdentifierSource|undefined),
|
|
@@ -356,7 +368,7 @@ class GoogleAdsApi {
|
|
|
356
368
|
async getReport(customerId, loginCustomerId, query) {
|
|
357
369
|
const request = new SearchGoogleAdsRequest({
|
|
358
370
|
query,
|
|
359
|
-
customerId:
|
|
371
|
+
customerId: getCleanCid(customerId),
|
|
360
372
|
});
|
|
361
373
|
return this.getReport_(request, loginCustomerId, true);
|
|
362
374
|
}
|
|
@@ -382,7 +394,7 @@ class GoogleAdsApi {
|
|
|
382
394
|
const request = new SearchGoogleAdsRequest(
|
|
383
395
|
Object.assign({
|
|
384
396
|
query,
|
|
385
|
-
customerId:
|
|
397
|
+
customerId: getCleanCid(customerId),
|
|
386
398
|
pageSize: 10000,
|
|
387
399
|
}, options)
|
|
388
400
|
);
|
|
@@ -413,7 +425,6 @@ class GoogleAdsApi {
|
|
|
413
425
|
return result;
|
|
414
426
|
}
|
|
415
427
|
|
|
416
|
-
//TODO: Test a big report see how the event 'data' is triggered
|
|
417
428
|
/**
|
|
418
429
|
* Gets stream report of a given Customer account. The stream will send
|
|
419
430
|
* `SearchGoogleAdsResponse` objects with the event 'data'.
|
|
@@ -426,7 +437,7 @@ class GoogleAdsApi {
|
|
|
426
437
|
const client = await this.getGoogleAdsServiceClient_();
|
|
427
438
|
const request = new SearchGoogleAdsRequest({
|
|
428
439
|
query,
|
|
429
|
-
customerId:
|
|
440
|
+
customerId: getCleanCid(customerId),
|
|
430
441
|
});
|
|
431
442
|
const callOptions = this.getCallOptions_(loginCustomerId);
|
|
432
443
|
const response = await client.searchStream(request, callOptions);
|
|
@@ -441,11 +452,11 @@ class GoogleAdsApi {
|
|
|
441
452
|
* @param {string} customerId
|
|
442
453
|
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
443
454
|
* @param {string} query A Google Ads Query string.
|
|
444
|
-
* @param {boolean}
|
|
445
|
-
* @return {!Promise<
|
|
455
|
+
* @param {boolean} snakeCase Output JSON objects in snake_case.
|
|
456
|
+
* @return {!Promise<stream>}
|
|
446
457
|
*/
|
|
447
458
|
async cleanedStreamReport(customerId, loginCustomerId, query,
|
|
448
|
-
|
|
459
|
+
snakeCase = false) {
|
|
449
460
|
const cleanReportStream = new Transform({
|
|
450
461
|
writableObjectMode: true,
|
|
451
462
|
transform(chunk, encoding, callback) {
|
|
@@ -454,7 +465,7 @@ class GoogleAdsApi {
|
|
|
454
465
|
return path.split('.').map(changeNamingFromSnakeToLowerCamel).join('.');
|
|
455
466
|
});
|
|
456
467
|
const extractor = extractObject(camelPaths);
|
|
457
|
-
const results =
|
|
468
|
+
const results = snakeCase
|
|
458
469
|
? chunk.results.map(extractor).map(changeObjectNamingFromLowerCamelToSnake)
|
|
459
470
|
: chunk.results.map(extractor);
|
|
460
471
|
// Add a line break after each chunk to keep files in proper format.
|
|
@@ -467,25 +478,69 @@ class GoogleAdsApi {
|
|
|
467
478
|
.pipe(cleanReportStream);
|
|
468
479
|
}
|
|
469
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Gets the report stream through REST interface.
|
|
483
|
+
* @param {string} customerId
|
|
484
|
+
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
485
|
+
* @param {string} query A Google Ads Query string.
|
|
486
|
+
* @return {!Promise<stream>}
|
|
487
|
+
*/
|
|
488
|
+
async restStreamReport(customerId, loginCustomerId, query) {
|
|
489
|
+
await this.authClient.prepareCredentials();
|
|
490
|
+
const headers = Object.assign(
|
|
491
|
+
await this.authClient.getDefaultAuth().getRequestHeaders(),
|
|
492
|
+
this.getGoogleAdsHeaders_(loginCustomerId)
|
|
493
|
+
);
|
|
494
|
+
const options = {
|
|
495
|
+
baseURL: `${API_ENDPOINT}/${API_VERSION}/`,
|
|
496
|
+
url: `customers/${getCleanCid(customerId)}/googleAds:searchStream`,
|
|
497
|
+
headers,
|
|
498
|
+
data: { query },
|
|
499
|
+
method: 'POST',
|
|
500
|
+
responseType: 'stream',
|
|
501
|
+
};
|
|
502
|
+
const response = await gaxiosRequest(options);
|
|
503
|
+
return response.data;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Gets the report stream through REST interface.
|
|
508
|
+
* Based on the `fieldMask` in the response to filter out
|
|
509
|
+
* selected fields of the report and returns an array of JSON format strings
|
|
510
|
+
* with the delimit of a line breaker.
|
|
511
|
+
* @param {string} customerId
|
|
512
|
+
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
513
|
+
* @param {string} query A Google Ads Query string.
|
|
514
|
+
* @param {boolean} snakeCase Output JSON objects in snake_case.
|
|
515
|
+
* @return {!Promise<stream>}
|
|
516
|
+
*/
|
|
517
|
+
async cleanedRestStreamReport(customerId, loginCustomerId, query,
|
|
518
|
+
snakeCase = false) {
|
|
519
|
+
const transform = new RestSearchStreamTransform(snakeCase);
|
|
520
|
+
const stream =
|
|
521
|
+
await this.restStreamReport(customerId, loginCustomerId, query);
|
|
522
|
+
return stream.on('error', (error) => transform.emit('error', error))
|
|
523
|
+
.pipe(transform);
|
|
524
|
+
}
|
|
525
|
+
|
|
470
526
|
/**
|
|
471
527
|
* Returns resources information from Google Ads API. see:
|
|
472
528
|
* https://developers.google.com/google-ads/api/docs/concepts/field-service
|
|
473
529
|
* Note, it looks like this function doesn't check the CID, just using
|
|
474
530
|
* developer token and OAuth.
|
|
475
|
-
* @param {string|number} loginCustomerId Login customer account ID.
|
|
476
531
|
* @param {Array<string>} adFields Array of Ad fields.
|
|
477
532
|
* @param {Array<string>} metadata Select fields, default values are:
|
|
478
533
|
* name, data_type, is_repeated, type_url.
|
|
479
534
|
* @return {!Promise<!Array<GoogleAdsField>>}
|
|
480
535
|
*/
|
|
481
|
-
async
|
|
482
|
-
'name', 'data_type', 'is_repeated', 'type_url',]) {
|
|
536
|
+
async searchReportField(adFields,
|
|
537
|
+
metadata = ['name', 'data_type', 'is_repeated', 'type_url',]) {
|
|
483
538
|
const client = await this.getGoogleAdsFieldServiceClient_();
|
|
484
539
|
const selectClause = metadata.join(',');
|
|
485
540
|
const fields = adFields.join('","');
|
|
486
541
|
const query = `SELECT ${selectClause} WHERE name IN ("${fields}")`;
|
|
487
542
|
const request = new SearchGoogleAdsFieldsRequest({ query });
|
|
488
|
-
const callOptions = this.getCallOptions_(
|
|
543
|
+
const callOptions = this.getCallOptions_();
|
|
489
544
|
const [results] = await client.searchGoogleAdsFields(request, callOptions);
|
|
490
545
|
return results;
|
|
491
546
|
}
|
|
@@ -569,8 +624,8 @@ class GoogleAdsApi {
|
|
|
569
624
|
functionName, propertyForDebug) {
|
|
570
625
|
/** @type {!ConversionConfig} */
|
|
571
626
|
const adsConfig = this.getCamelConfig_(conversionConfig);
|
|
572
|
-
adsConfig.customerId =
|
|
573
|
-
adsConfig.loginCustomerId =
|
|
627
|
+
adsConfig.customerId = getCleanCid(customerId);
|
|
628
|
+
adsConfig.loginCustomerId = getCleanCid(loginCustomerId);
|
|
574
629
|
/**
|
|
575
630
|
* Sends a batch of hits to Google Ads API.
|
|
576
631
|
* @param {!Array<string>} lines Data for single request. It should be
|
|
@@ -885,7 +940,7 @@ class GoogleAdsApi {
|
|
|
885
940
|
SELECT user_list.id, user_list.resource_name
|
|
886
941
|
FROM user_list
|
|
887
942
|
WHERE user_list.name = '${listName}'
|
|
888
|
-
AND customer.id = ${
|
|
943
|
+
AND customer.id = ${getCleanCid(customerId)}
|
|
889
944
|
AND user_list.type = CRM_BASED
|
|
890
945
|
AND user_list.membership_status = OPEN
|
|
891
946
|
AND user_list.crm_based_user_list.upload_key_type = ${uploadKeyType}
|
|
@@ -915,7 +970,7 @@ class GoogleAdsApi {
|
|
|
915
970
|
crmBasedUserList: { uploadKeyType },
|
|
916
971
|
});
|
|
917
972
|
const request = new MutateUserListsRequest({
|
|
918
|
-
customerId:
|
|
973
|
+
customerId: getCleanCid(customerId),
|
|
919
974
|
operations: [{ create: userList }],
|
|
920
975
|
validateOnly: this.debugMode, // when true makes no changes
|
|
921
976
|
partialFailure: false, // Simplify error handling in creating userlist
|
|
@@ -1021,9 +1076,9 @@ class GoogleAdsApi {
|
|
|
1021
1076
|
const operations = userDataList.map(
|
|
1022
1077
|
(userData) => new UserDataOperation({ [operation]: new UserData(userData) })
|
|
1023
1078
|
);
|
|
1024
|
-
const metadata = this.buildCustomerMatchUserListMetadata_(
|
|
1079
|
+
const metadata = this.buildCustomerMatchUserListMetadata_(config);
|
|
1025
1080
|
const request = new UploadUserDataRequest({
|
|
1026
|
-
customerId:
|
|
1081
|
+
customerId: getCleanCid(customerId),
|
|
1027
1082
|
operations,
|
|
1028
1083
|
customerMatchUserListMetadata: metadata,
|
|
1029
1084
|
});
|
|
@@ -1035,16 +1090,20 @@ class GoogleAdsApi {
|
|
|
1035
1090
|
/**
|
|
1036
1091
|
* Creates CustomerMatchUserListMetadata.
|
|
1037
1092
|
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/CustomerMatchUserListMetadata
|
|
1038
|
-
* @param {
|
|
1039
|
-
*
|
|
1093
|
+
* @param {{
|
|
1094
|
+
* customerId: string,
|
|
1095
|
+
* listId: string,
|
|
1096
|
+
* customerMatchUserListMetadata: undefined|!CustomerMatchUserListMetadata
|
|
1097
|
+
* }} config Configuration for CustomerMatchUserListMetadata
|
|
1040
1098
|
* @return {!CustomerMatchUserListMetadata}
|
|
1041
1099
|
* @private
|
|
1042
1100
|
*/
|
|
1043
|
-
buildCustomerMatchUserListMetadata_(
|
|
1044
|
-
const
|
|
1045
|
-
|
|
1101
|
+
buildCustomerMatchUserListMetadata_(config) {
|
|
1102
|
+
const { customerId, listId, customerMatchUserListMetadata } = config;
|
|
1103
|
+
const resourceName = `customers/${customerId}/userLists/${listId}`;
|
|
1104
|
+
return new CustomerMatchUserListMetadata(Object.assign({
|
|
1046
1105
|
userList: resourceName,
|
|
1047
|
-
});
|
|
1106
|
+
}, customerMatchUserListMetadata));
|
|
1048
1107
|
}
|
|
1049
1108
|
|
|
1050
1109
|
/**
|
|
@@ -1090,8 +1149,7 @@ class GoogleAdsApi {
|
|
|
1090
1149
|
const jobData = { type };
|
|
1091
1150
|
// https://developers.google.com/google-ads/api/rest/reference/rest/latest/OfflineUserDataJobs?hl=en#CustomerMatchUserListMetadata
|
|
1092
1151
|
if (type.startsWith('CUSTOMER_MATCH')) {
|
|
1093
|
-
const metadata = this.buildCustomerMatchUserListMetadata_(
|
|
1094
|
-
listId);
|
|
1152
|
+
const metadata = this.buildCustomerMatchUserListMetadata_(config);
|
|
1095
1153
|
jobData.customerMatchUserListMetadata = metadata;
|
|
1096
1154
|
// https://developers.google.com/google-ads/api/rest/reference/rest/latest/OfflineUserDataJob?hl=en#StoreSalesMetadata
|
|
1097
1155
|
} else if (type.startsWith('STORE_SALES')) {
|
|
@@ -1105,7 +1163,7 @@ class GoogleAdsApi {
|
|
|
1105
1163
|
}
|
|
1106
1164
|
const job = new OfflineUserDataJob(jobData);
|
|
1107
1165
|
const request = new CreateOfflineUserDataJobRequest({
|
|
1108
|
-
customerId:
|
|
1166
|
+
customerId: getCleanCid(customerId),
|
|
1109
1167
|
job,
|
|
1110
1168
|
validateOnly: this.debugMode, // when true makes no changes
|
|
1111
1169
|
enableMatchRateRangePreview: true,
|
|
@@ -1258,16 +1316,6 @@ class GoogleAdsApi {
|
|
|
1258
1316
|
}
|
|
1259
1317
|
}
|
|
1260
1318
|
|
|
1261
|
-
/**
|
|
1262
|
-
* Returns a integer format CID by removing dashes.
|
|
1263
|
-
* @param {string} cid
|
|
1264
|
-
* @return {string}
|
|
1265
|
-
* @private
|
|
1266
|
-
*/
|
|
1267
|
-
getCleanCid_(cid) {
|
|
1268
|
-
return cid.toString().replace(/-/g, '');
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
1319
|
/**
|
|
1272
1320
|
* Historically, we used a 3rd party library that adopted snake naming
|
|
1273
1321
|
* convention as the protobuf files and API documents. However, the
|
|
@@ -1289,10 +1337,11 @@ class GoogleAdsApi {
|
|
|
1289
1337
|
* @private
|
|
1290
1338
|
*/
|
|
1291
1339
|
getGoogleAdsHeaders_(loginCustomerId) {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
}
|
|
1340
|
+
const headers = { 'developer-token': this.developerToken };
|
|
1341
|
+
if (loginCustomerId) {
|
|
1342
|
+
headers['login-customer-id'] = getCleanCid(loginCustomerId);
|
|
1343
|
+
}
|
|
1344
|
+
return headers;
|
|
1296
1345
|
}
|
|
1297
1346
|
|
|
1298
1347
|
/**
|
|
@@ -1305,7 +1354,7 @@ class GoogleAdsApi {
|
|
|
1305
1354
|
getCallOptions_(loginCustomerId) {
|
|
1306
1355
|
return {
|
|
1307
1356
|
otherArgs: {
|
|
1308
|
-
headers: this.getGoogleAdsHeaders_(
|
|
1357
|
+
headers: this.getGoogleAdsHeaders_(loginCustomerId),
|
|
1309
1358
|
},
|
|
1310
1359
|
};
|
|
1311
1360
|
}
|
package/src/apis/index.js
CHANGED