google-ads-api 19.0.2 → 19.0.3-rest-beta
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/build/src/client.d.ts +1 -0
- package/build/src/client.js +1 -0
- package/build/src/customer.d.ts +6 -0
- package/build/src/customer.js +203 -73
- package/build/src/parserRest.d.ts +4 -0
- package/build/src/parserRest.js +88 -0
- package/build/src/protos/autogen/fields.d.ts +1 -0
- package/build/src/protos/autogen/fields.js +3 -1
- package/build/src/protos/autogen/serviceFactory.js +1 -1
- package/build/src/protos/index.d.ts +1 -1
- package/build/src/protos/index.js +2 -1
- package/build/src/query.js +1 -1
- package/build/src/service.d.ts +1 -0
- package/build/src/service.js +35 -14
- package/build/src/testUtils.d.ts +38 -0
- package/build/src/testUtils.js +76 -5
- package/build/src/utils.d.ts +0 -5
- package/build/src/utils.js +0 -15
- package/package.json +15 -5
- package/CHANGELOG.md +0 -44
|
@@ -5,7 +5,7 @@ const service_1 = require("../../service");
|
|
|
5
5
|
const index_1 = require("../index");
|
|
6
6
|
class ServiceFactory extends service_1.Service {
|
|
7
7
|
constructor(clientOptions, customerOptions, hooks) {
|
|
8
|
-
super(clientOptions, customerOptions, hooks
|
|
8
|
+
super(clientOptions, customerOptions, hooks ?? {});
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* @link https://developers.google.com/google-ads/api/reference/rpc/v19/AccountBudgetProposalService
|
|
@@ -6,7 +6,7 @@ export import resources = protos.google.ads.googleads.v19.resources;
|
|
|
6
6
|
export import services = protos.google.ads.googleads.v19.services;
|
|
7
7
|
export import internalEnums = protos.google.ads.googleads.v19.enums;
|
|
8
8
|
export { enums } from "./autogen/enums";
|
|
9
|
-
export { fields } from "./autogen/fields";
|
|
9
|
+
export { fields, fieldDataTypes } from "./autogen/fields";
|
|
10
10
|
export { GoogleAdsServiceClient } from "google-ads-node";
|
|
11
11
|
export type AllServices = Omit<typeof allProtos, typeof VERSION>;
|
|
12
12
|
export type ServiceName = keyof Omit<typeof allProtos, typeof VERSION>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.longrunning = exports.protobuf = exports.GoogleAdsServiceClient = exports.fields = exports.enums = exports.internalEnums = exports.services = exports.resources = exports.errors = exports.common = exports.VERSION = void 0;
|
|
3
|
+
exports.longrunning = exports.protobuf = exports.GoogleAdsServiceClient = exports.fieldDataTypes = exports.fields = exports.enums = exports.internalEnums = exports.services = exports.resources = exports.errors = exports.common = exports.VERSION = void 0;
|
|
4
4
|
const google_ads_node_1 = require("google-ads-node");
|
|
5
5
|
const version_1 = require("../version");
|
|
6
6
|
// "as vN" is required to avoid type issues later on
|
|
@@ -17,6 +17,7 @@ var enums_1 = require("./autogen/enums");
|
|
|
17
17
|
Object.defineProperty(exports, "enums", { enumerable: true, get: function () { return enums_1.enums; } });
|
|
18
18
|
var fields_1 = require("./autogen/fields");
|
|
19
19
|
Object.defineProperty(exports, "fields", { enumerable: true, get: function () { return fields_1.fields; } });
|
|
20
|
+
Object.defineProperty(exports, "fieldDataTypes", { enumerable: true, get: function () { return fields_1.fieldDataTypes; } });
|
|
20
21
|
// Common service used for report/query methods
|
|
21
22
|
var google_ads_node_2 = require("google-ads-node");
|
|
22
23
|
Object.defineProperty(exports, "GoogleAdsServiceClient", { enumerable: true, get: function () { return google_ads_node_2.GoogleAdsServiceClient; } });
|
package/build/src/query.js
CHANGED
|
@@ -51,7 +51,7 @@ exports.QueryError = {
|
|
|
51
51
|
UNDEFINED_ENTITY: "The entity of the query must be defined.",
|
|
52
52
|
};
|
|
53
53
|
function buildSelectClause(attributes, metrics, segments) {
|
|
54
|
-
if (!
|
|
54
|
+
if (!attributes?.length && !metrics?.length && !segments?.length) {
|
|
55
55
|
throw new Error(exports.QueryError.MISSING_FIELDS);
|
|
56
56
|
}
|
|
57
57
|
const selections = [
|
package/build/src/service.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare class Service {
|
|
|
16
16
|
get credentials(): CustomerCredentials;
|
|
17
17
|
protected get callHeaders(): CallHeaders;
|
|
18
18
|
private getCredentials;
|
|
19
|
+
getAccessToken(): Promise<string>;
|
|
19
20
|
protected loadService<T = AllServices>(service: ServiceName): T;
|
|
20
21
|
protected getGoogleAdsError(error: Error): errors.GoogleAdsFailure | Error;
|
|
21
22
|
private decodeGoogleAdsFailureBuffer;
|
package/build/src/service.js
CHANGED
|
@@ -14,18 +14,26 @@ const ttlcache_1 = __importDefault(require("@isaacs/ttlcache"));
|
|
|
14
14
|
exports.FAILURE_KEY = `google.ads.googleads.${version_1.googleAdsVersion}.errors.googleadsfailure-bin`;
|
|
15
15
|
// A global service cache to avoid re-initialising services
|
|
16
16
|
const serviceCache = new ttlcache_1.default({
|
|
17
|
-
max:
|
|
17
|
+
max: 1_000,
|
|
18
18
|
ttl: 10 * 60 * 1000, // 10 minutes
|
|
19
19
|
dispose: async (service) => {
|
|
20
20
|
// Close connections when services are removed from the cache
|
|
21
21
|
await service.close();
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
|
+
// A global access token cache used by REST calls. Issued tokens expire after 1 hour, so we cache them for 50 minutes.
|
|
25
|
+
const accessTokenCache = new ttlcache_1.default({
|
|
26
|
+
max: 100_000,
|
|
27
|
+
ttl: 50 * 60 * 1000, // 50 minutes
|
|
28
|
+
});
|
|
24
29
|
class Service {
|
|
30
|
+
clientOptions;
|
|
31
|
+
customerOptions;
|
|
32
|
+
hooks;
|
|
25
33
|
constructor(clientOptions, customerOptions, hooks) {
|
|
26
34
|
this.clientOptions = clientOptions;
|
|
27
35
|
this.customerOptions = customerOptions;
|
|
28
|
-
this.hooks = hooks
|
|
36
|
+
this.hooks = hooks ?? {};
|
|
29
37
|
// @ts-expect-error All fields don't need to be set here
|
|
30
38
|
this.serviceCache = {};
|
|
31
39
|
}
|
|
@@ -48,12 +56,30 @@ class Service {
|
|
|
48
56
|
}
|
|
49
57
|
return headers;
|
|
50
58
|
}
|
|
59
|
+
// Used only by gRPC calls
|
|
51
60
|
getCredentials() {
|
|
52
61
|
const sslCreds = google_gax_1.grpc.credentials.createSsl();
|
|
53
62
|
const authClient = new google_auth_library_1.UserRefreshClient(this.clientOptions.client_id, this.clientOptions.client_secret, this.customerOptions.refresh_token);
|
|
54
63
|
const credentials = google_gax_1.grpc.credentials.combineChannelCredentials(sslCreds, google_gax_1.grpc.credentials.createFromGoogleCredential(authClient));
|
|
55
64
|
return credentials;
|
|
56
65
|
}
|
|
66
|
+
// Used only by REST calls
|
|
67
|
+
async getAccessToken() {
|
|
68
|
+
const cachedToken = accessTokenCache.get(this.customerOptions.refresh_token);
|
|
69
|
+
if (cachedToken) {
|
|
70
|
+
return cachedToken;
|
|
71
|
+
}
|
|
72
|
+
const oAuth2Client = new google_auth_library_1.OAuth2Client(this.clientOptions.client_id, this.clientOptions.client_secret);
|
|
73
|
+
oAuth2Client.setCredentials({
|
|
74
|
+
refresh_token: this.customerOptions.refresh_token,
|
|
75
|
+
});
|
|
76
|
+
const { token } = await oAuth2Client.getAccessToken();
|
|
77
|
+
if (typeof token !== "string") {
|
|
78
|
+
throw new Error("Failed to retrieve access token");
|
|
79
|
+
}
|
|
80
|
+
accessTokenCache.set(this.customerOptions.refresh_token, token);
|
|
81
|
+
return token;
|
|
82
|
+
}
|
|
57
83
|
loadService(service) {
|
|
58
84
|
const serviceCacheKey = `${service}_${this.customerOptions.refresh_token}`;
|
|
59
85
|
if (serviceCache.has(serviceCacheKey)) {
|
|
@@ -72,9 +98,8 @@ class Service {
|
|
|
72
98
|
return client;
|
|
73
99
|
}
|
|
74
100
|
getGoogleAdsError(error) {
|
|
75
|
-
var _a;
|
|
76
101
|
// @ts-expect-error No type exists for GA query error
|
|
77
|
-
if (typeof
|
|
102
|
+
if (typeof error?.metadata?.internalRepr.get(exports.FAILURE_KEY) === "undefined") {
|
|
78
103
|
return error;
|
|
79
104
|
}
|
|
80
105
|
// @ts-expect-error No type exists for GA query error
|
|
@@ -86,13 +111,12 @@ class Service {
|
|
|
86
111
|
return googleAdsFailure;
|
|
87
112
|
}
|
|
88
113
|
decodePartialFailureError(response) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
!(response === null || response === void 0 ? void 0 : response.partial_failure_error)) {
|
|
114
|
+
if (typeof response?.partial_failure_error === "undefined" ||
|
|
115
|
+
!response?.partial_failure_error) {
|
|
92
116
|
return response;
|
|
93
117
|
}
|
|
94
118
|
const { details } = response.partial_failure_error;
|
|
95
|
-
const buffer =
|
|
119
|
+
const buffer = details?.find((d) => d.type_url.includes("errors.GoogleAdsFailure"))?.value;
|
|
96
120
|
if (typeof buffer === "undefined") {
|
|
97
121
|
return response;
|
|
98
122
|
}
|
|
@@ -123,15 +147,13 @@ class Service {
|
|
|
123
147
|
buildMutationRequestAndService(mutations, options) {
|
|
124
148
|
const service = this.loadService("GoogleAdsServiceClient");
|
|
125
149
|
const mutateOperations = mutations.map((mutation) => {
|
|
126
|
-
var _a, _b;
|
|
127
150
|
const opKey = (0, utils_1.toSnakeCase)(`${mutation.entity}Operation`);
|
|
128
151
|
const operation = {
|
|
129
|
-
[
|
|
152
|
+
[mutation.operation ?? "create"]: mutation.resource,
|
|
130
153
|
};
|
|
131
154
|
if (mutation.operation === "create" &&
|
|
132
|
-
(
|
|
133
155
|
//@ts-ignore
|
|
134
|
-
|
|
156
|
+
mutation?.exempt_policy_violation_keys?.length) {
|
|
135
157
|
//@ts-ignore
|
|
136
158
|
operation.exempt_policy_violation_keys =
|
|
137
159
|
mutation.exempt_policy_violation_keys;
|
|
@@ -154,13 +176,12 @@ class Service {
|
|
|
154
176
|
}
|
|
155
177
|
buildOperations(type, entities, message) {
|
|
156
178
|
const ops = entities.map((e) => {
|
|
157
|
-
var _a;
|
|
158
179
|
const op = {
|
|
159
180
|
[type]: e,
|
|
160
181
|
operation: type,
|
|
161
182
|
};
|
|
162
183
|
//@ts-ignore
|
|
163
|
-
if (type === "create" &&
|
|
184
|
+
if (type === "create" && e?.exempt_policy_violation_keys?.length) {
|
|
164
185
|
// @ts-expect-error Field required for policy violation exemptions
|
|
165
186
|
op.exempt_policy_violation_keys = e.exempt_policy_violation_keys;
|
|
166
187
|
//@ts-ignore
|
package/build/src/testUtils.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Readable } from "stream";
|
|
1
2
|
import { Customer } from "./customer";
|
|
2
3
|
import { Hooks } from "./hooks";
|
|
3
4
|
import { errors, GoogleAdsServiceClient, services } from "./protos";
|
|
@@ -11,7 +12,39 @@ export declare const MOCK_LOGIN_CID = "MOCK LOGIN CID";
|
|
|
11
12
|
export declare const mockGaqlQuery = "SELECT campaign.resource_name FROM campaign LIMIT 1";
|
|
12
13
|
export declare const mockReportOptions: ReportOptions;
|
|
13
14
|
export declare const mockMutations: MutateOperation<any>[];
|
|
15
|
+
export declare const mockSearchRawResult: {
|
|
16
|
+
totalResultsCount: number;
|
|
17
|
+
results: {
|
|
18
|
+
campaign: {
|
|
19
|
+
resourceName: string;
|
|
20
|
+
};
|
|
21
|
+
}[];
|
|
22
|
+
}[];
|
|
23
|
+
export declare const mockSearchRawResultWithSummaryRow: ({
|
|
24
|
+
totalResultsCount: number;
|
|
25
|
+
results: {
|
|
26
|
+
campaign: {
|
|
27
|
+
resourceName: string;
|
|
28
|
+
};
|
|
29
|
+
}[];
|
|
30
|
+
summaryRow?: undefined;
|
|
31
|
+
} | {
|
|
32
|
+
summaryRow: {
|
|
33
|
+
metrics: {
|
|
34
|
+
clicks: number;
|
|
35
|
+
impressions: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
totalResultsCount?: undefined;
|
|
39
|
+
results?: undefined;
|
|
40
|
+
})[];
|
|
14
41
|
export declare const mockQueryReturnValue: services.IGoogleAdsRow[];
|
|
42
|
+
export declare const mockQueryReturnValueWithSummaryRow: services.IGoogleAdsRow[];
|
|
43
|
+
export declare const mockQueryReturnValueUnparsed: {
|
|
44
|
+
campaign: {
|
|
45
|
+
resourceName: string;
|
|
46
|
+
};
|
|
47
|
+
}[];
|
|
15
48
|
export declare const mockSummaryRow: services.IGoogleAdsRow;
|
|
16
49
|
export declare const mockTotalResultsCount = 23;
|
|
17
50
|
export declare const mockMutationReturnValue: services.MutateGoogleAdsResponse;
|
|
@@ -26,6 +59,10 @@ export declare const mockError: {
|
|
|
26
59
|
export declare const mockErrorMessage = "mock error message";
|
|
27
60
|
export declare const mockParseValue: services.IGoogleAdsRow;
|
|
28
61
|
export declare const mockParsedValues: services.IGoogleAdsRow[];
|
|
62
|
+
export declare const mockStream: (data?: any) => Readable;
|
|
63
|
+
export declare function mockGetAccessToken(customer: Customer): jest.SpyInstance;
|
|
64
|
+
export declare const mockStreamWithSummaryRow: () => Readable;
|
|
65
|
+
export declare const mockStreamWithBadData: () => Readable;
|
|
29
66
|
export declare function mockPaginatedSearch(customer: Customer, includeTotalResultsCount?: boolean): jest.SpyInstance;
|
|
30
67
|
export declare function mockSearchOnce({ customer, response, nextPageToken, includeTotalResultsCount, }: {
|
|
31
68
|
customer: Customer;
|
|
@@ -61,6 +98,7 @@ export declare function mockBuildMutateRequestAndService({ customer, shouldThrow
|
|
|
61
98
|
export declare function mockGetGoogleAdsError(customer: Customer): jest.SpyInstance;
|
|
62
99
|
export declare function mockQuery(customer: Customer): jest.SpyInstance;
|
|
63
100
|
export declare function mockParse(mockParsedValues: services.IGoogleAdsRow[]): jest.SpyInstance;
|
|
101
|
+
export declare function mockParseRest(mockParsedValues: services.IGoogleAdsRow[]): jest.SpyInstance;
|
|
64
102
|
export declare function noopParser(rows: services.IGoogleAdsRow[]): services.IGoogleAdsRow[];
|
|
65
103
|
export declare function mockMethod(): {
|
|
66
104
|
method(): void;
|
package/build/src/testUtils.js
CHANGED
|
@@ -22,8 +22,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
25
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.mockParsedValues = exports.mockParseValue = exports.mockErrorMessage = exports.mockError = exports.mockMutationReturnValue = exports.mockTotalResultsCount = exports.mockSummaryRow = exports.mockQueryReturnValue = exports.mockMutations = exports.mockReportOptions = exports.mockGaqlQuery = exports.MOCK_LOGIN_CID = exports.MOCK_CID = exports.MOCK_REFRESH_TOKEN = exports.MOCK_DEVELOPER_TOKEN = exports.MOCK_CLIENT_SECRET = exports.MOCK_CLIENT_ID = void 0;
|
|
29
|
+
exports.mockStreamWithBadData = exports.mockStreamWithSummaryRow = exports.mockStream = exports.mockParsedValues = exports.mockParseValue = exports.mockErrorMessage = exports.mockError = exports.mockMutationReturnValue = exports.mockTotalResultsCount = exports.mockSummaryRow = exports.mockQueryReturnValueUnparsed = exports.mockQueryReturnValueWithSummaryRow = exports.mockQueryReturnValue = exports.mockSearchRawResultWithSummaryRow = exports.mockSearchRawResult = exports.mockMutations = exports.mockReportOptions = exports.mockGaqlQuery = exports.MOCK_LOGIN_CID = exports.MOCK_CID = exports.MOCK_REFRESH_TOKEN = exports.MOCK_DEVELOPER_TOKEN = exports.MOCK_CLIENT_SECRET = exports.MOCK_CLIENT_ID = void 0;
|
|
30
|
+
exports.mockGetAccessToken = mockGetAccessToken;
|
|
27
31
|
exports.mockPaginatedSearch = mockPaginatedSearch;
|
|
28
32
|
exports.mockSearchOnce = mockSearchOnce;
|
|
29
33
|
exports.mockBuildSearchStreamRequestAndService = mockBuildSearchStreamRequestAndService;
|
|
@@ -32,6 +36,7 @@ exports.mockBuildMutateRequestAndService = mockBuildMutateRequestAndService;
|
|
|
32
36
|
exports.mockGetGoogleAdsError = mockGetGoogleAdsError;
|
|
33
37
|
exports.mockQuery = mockQuery;
|
|
34
38
|
exports.mockParse = mockParse;
|
|
39
|
+
exports.mockParseRest = mockParseRest;
|
|
35
40
|
exports.noopParser = noopParser;
|
|
36
41
|
exports.mockMethod = mockMethod;
|
|
37
42
|
exports.failTestIfExecuted = failTestIfExecuted;
|
|
@@ -39,7 +44,9 @@ exports.newCustomer = newCustomer;
|
|
|
39
44
|
const stream_1 = require("stream");
|
|
40
45
|
const customer_1 = require("./customer");
|
|
41
46
|
const parser = __importStar(require("./parser"));
|
|
47
|
+
const parserRest = __importStar(require("./parserRest"));
|
|
42
48
|
const protos_1 = require("./protos");
|
|
49
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
43
50
|
exports.MOCK_CLIENT_ID = "MOCK CLIENT ID";
|
|
44
51
|
exports.MOCK_CLIENT_SECRET = "MOCK CLIENT SECRET";
|
|
45
52
|
exports.MOCK_DEVELOPER_TOKEN = "MOCK DEVELOPER TOKEN";
|
|
@@ -55,11 +62,45 @@ exports.mockReportOptions = {
|
|
|
55
62
|
exports.mockMutations = [
|
|
56
63
|
{ resource: "abc", entity: "campaign", operation: "create" },
|
|
57
64
|
];
|
|
65
|
+
exports.mockSearchRawResult = [
|
|
66
|
+
{
|
|
67
|
+
totalResultsCount: 23,
|
|
68
|
+
results: [
|
|
69
|
+
{ campaign: { resourceName: "customers/1/campaigns/11" } },
|
|
70
|
+
{ campaign: { resourceName: "customers/2/campaigns/22" } },
|
|
71
|
+
{ campaign: { resourceName: "customers/3/campaigns/33" } },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
exports.mockSearchRawResultWithSummaryRow = [
|
|
76
|
+
{
|
|
77
|
+
totalResultsCount: 23,
|
|
78
|
+
results: [
|
|
79
|
+
{ campaign: { resourceName: "customers/1/campaigns/11" } },
|
|
80
|
+
{ campaign: { resourceName: "customers/2/campaigns/22" } },
|
|
81
|
+
{ campaign: { resourceName: "customers/3/campaigns/33" } },
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
summaryRow: { metrics: { clicks: 90, impressions: 153 } },
|
|
86
|
+
},
|
|
87
|
+
];
|
|
58
88
|
exports.mockQueryReturnValue = [
|
|
59
89
|
{ campaign: { resource_name: "customers/1/campaigns/11" } },
|
|
60
90
|
{ campaign: { resource_name: "customers/2/campaigns/22" } },
|
|
61
91
|
{ campaign: { resource_name: "customers/3/campaigns/33" } },
|
|
62
92
|
];
|
|
93
|
+
exports.mockQueryReturnValueWithSummaryRow = [
|
|
94
|
+
{ campaign: { resource_name: "customers/1/campaigns/11" } },
|
|
95
|
+
{ campaign: { resource_name: "customers/2/campaigns/22" } },
|
|
96
|
+
{ campaign: { resource_name: "customers/3/campaigns/33" } },
|
|
97
|
+
{ metrics: { clicks: 90, impressions: 153 } },
|
|
98
|
+
];
|
|
99
|
+
exports.mockQueryReturnValueUnparsed = [
|
|
100
|
+
{ campaign: { resourceName: "customers/1/campaigns/11" } },
|
|
101
|
+
{ campaign: { resourceName: "customers/2/campaigns/22" } },
|
|
102
|
+
{ campaign: { resourceName: "customers/3/campaigns/33" } },
|
|
103
|
+
];
|
|
63
104
|
exports.mockSummaryRow = {
|
|
64
105
|
metrics: { clicks: 90, impressions: 153 },
|
|
65
106
|
};
|
|
@@ -87,17 +128,42 @@ exports.mockParsedValues = [
|
|
|
87
128
|
exports.mockParseValue,
|
|
88
129
|
exports.mockParseValue,
|
|
89
130
|
];
|
|
131
|
+
// Returns a stream that emits the provided values
|
|
132
|
+
const mockStream = function (data = exports.mockSearchRawResult) {
|
|
133
|
+
const chunks = lodash_1.default.chunk(JSON.stringify(data), 10).map((c) => c.join("")); // random splits
|
|
134
|
+
const stream = new stream_1.Readable({ objectMode: true });
|
|
135
|
+
chunks.forEach((value) => stream.push(new Buffer(value)));
|
|
136
|
+
stream.push(null);
|
|
137
|
+
return stream;
|
|
138
|
+
};
|
|
139
|
+
exports.mockStream = mockStream;
|
|
140
|
+
function mockGetAccessToken(customer) {
|
|
141
|
+
return (jest
|
|
142
|
+
.spyOn(customer, "getAccessToken")
|
|
143
|
+
// ts-expect-error
|
|
144
|
+
.mockImplementation(async () => {
|
|
145
|
+
return "mockedAccessTokenHere";
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
const mockStreamWithSummaryRow = function () {
|
|
149
|
+
return (0, exports.mockStream)(exports.mockSearchRawResultWithSummaryRow);
|
|
150
|
+
};
|
|
151
|
+
exports.mockStreamWithSummaryRow = mockStreamWithSummaryRow;
|
|
152
|
+
const mockStreamWithBadData = function () {
|
|
153
|
+
return (0, exports.mockStream)({ results: 66 });
|
|
154
|
+
};
|
|
155
|
+
exports.mockStreamWithBadData = mockStreamWithBadData;
|
|
90
156
|
function mockPaginatedSearch(customer, includeTotalResultsCount = false) {
|
|
91
157
|
return (jest
|
|
92
158
|
// @ts-expect-error private method
|
|
93
159
|
.spyOn(customer, "paginatedSearch")
|
|
94
160
|
// @ts-expect-error
|
|
95
|
-
.mockImplementation((gaqlQuery, requestOptions
|
|
161
|
+
.mockImplementation((gaqlQuery, requestOptions) => {
|
|
96
162
|
const totalResultsCount = includeTotalResultsCount
|
|
97
163
|
? exports.mockTotalResultsCount
|
|
98
164
|
: undefined;
|
|
99
165
|
return {
|
|
100
|
-
response:
|
|
166
|
+
response: exports.mockQueryReturnValue,
|
|
101
167
|
totalResultsCount,
|
|
102
168
|
};
|
|
103
169
|
}));
|
|
@@ -188,7 +254,7 @@ function mockBuildMutateRequestAndService({ customer, shouldThrow = false, reque
|
|
|
188
254
|
if (shouldThrow) {
|
|
189
255
|
throw new Error(exports.mockErrorMessage);
|
|
190
256
|
}
|
|
191
|
-
return [response
|
|
257
|
+
return [response ?? exports.mockMutationReturnValue];
|
|
192
258
|
},
|
|
193
259
|
};
|
|
194
260
|
const spyBuild = jest
|
|
@@ -198,7 +264,7 @@ function mockBuildMutateRequestAndService({ customer, shouldThrow = false, reque
|
|
|
198
264
|
.mockImplementation(() => {
|
|
199
265
|
return {
|
|
200
266
|
service: mockService,
|
|
201
|
-
request: request
|
|
267
|
+
request: request ?? {},
|
|
202
268
|
};
|
|
203
269
|
});
|
|
204
270
|
return { mockService, spyBuild };
|
|
@@ -225,6 +291,11 @@ function mockQuery(customer) {
|
|
|
225
291
|
function mockParse(mockParsedValues) {
|
|
226
292
|
return jest.spyOn(parser, "parse").mockImplementation(() => mockParsedValues);
|
|
227
293
|
}
|
|
294
|
+
function mockParseRest(mockParsedValues) {
|
|
295
|
+
return jest
|
|
296
|
+
.spyOn(parserRest, "decamelizeKeys")
|
|
297
|
+
.mockImplementation(() => mockParsedValues);
|
|
298
|
+
}
|
|
228
299
|
function noopParser(rows) {
|
|
229
300
|
return rows;
|
|
230
301
|
}
|
package/build/src/utils.d.ts
CHANGED
|
@@ -47,8 +47,3 @@ export declare function toCamelCase(str: string): string;
|
|
|
47
47
|
export declare function toSnakeCase(str: string): string;
|
|
48
48
|
export declare function recursiveFieldMaskSearch(data: Record<string, any>): string[];
|
|
49
49
|
export declare function getFieldMask(data: Record<string, any>): protobuf.FieldMask;
|
|
50
|
-
export declare function createNextChunkArrivedPromise(): {
|
|
51
|
-
newPromise: Promise<unknown>;
|
|
52
|
-
resolve: () => void;
|
|
53
|
-
reject: (error: Error) => void;
|
|
54
|
-
};
|
package/build/src/utils.js
CHANGED
|
@@ -8,7 +8,6 @@ exports.toCamelCase = toCamelCase;
|
|
|
8
8
|
exports.toSnakeCase = toSnakeCase;
|
|
9
9
|
exports.recursiveFieldMaskSearch = recursiveFieldMaskSearch;
|
|
10
10
|
exports.getFieldMask = getFieldMask;
|
|
11
|
-
exports.createNextChunkArrivedPromise = createNextChunkArrivedPromise;
|
|
12
11
|
const protos_1 = require("./protos");
|
|
13
12
|
/**
|
|
14
13
|
* @param micros Money value in micros format
|
|
@@ -100,17 +99,3 @@ function getFieldMask(data) {
|
|
|
100
99
|
paths,
|
|
101
100
|
});
|
|
102
101
|
}
|
|
103
|
-
function createNextChunkArrivedPromise() {
|
|
104
|
-
let resolvePromise = () => {
|
|
105
|
-
return;
|
|
106
|
-
};
|
|
107
|
-
let rejectPromise = (error) => {
|
|
108
|
-
throw error;
|
|
109
|
-
};
|
|
110
|
-
const newPromise = new Promise((resolve, reject) => {
|
|
111
|
-
// @ts-ignore
|
|
112
|
-
resolvePromise = resolve;
|
|
113
|
-
rejectPromise = reject;
|
|
114
|
-
});
|
|
115
|
-
return { newPromise, resolve: resolvePromise, reject: rejectPromise };
|
|
116
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "google-ads-api",
|
|
3
|
-
"version": "19.0.
|
|
3
|
+
"version": "19.0.3-rest-beta",
|
|
4
4
|
"description": "Google Ads API Client Library for Node.js",
|
|
5
5
|
"repository": "https://github.com/Opteo/google-ads-api",
|
|
6
6
|
"main": "build/src/index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"test": "jest",
|
|
12
12
|
"lint": "eslint . --ext .ts",
|
|
13
13
|
"build": "tsc",
|
|
14
|
-
"compile": "
|
|
14
|
+
"compile": "esbuild --bundle --platform=node ./scripts/index.ts --outfile=./build/scripts/index.js && node ./build/scripts/index.js",
|
|
15
15
|
"prepare": "rm -rf build && npm run build",
|
|
16
16
|
"node": "tsx"
|
|
17
17
|
},
|
|
@@ -19,21 +19,31 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@isaacs/ttlcache": "^1.2.2",
|
|
22
|
+
"axios": "^1.6.7",
|
|
23
|
+
"circ-json": "^1.0.4",
|
|
22
24
|
"google-ads-node": "15.0.0",
|
|
23
25
|
"google-auth-library": "^7.1.0",
|
|
24
26
|
"google-gax": "^4.4.1",
|
|
25
|
-
"long": "^4.0.0"
|
|
27
|
+
"long": "^4.0.0",
|
|
28
|
+
"map-obj": "^4.0.0",
|
|
29
|
+
"stream-json": "^1.8.0"
|
|
26
30
|
},
|
|
27
31
|
"devDependencies": {
|
|
28
32
|
"@types/jest": "^29.0.1",
|
|
33
|
+
"@types/lodash": "^4.14.202",
|
|
29
34
|
"@types/node": "^22.5.4",
|
|
30
35
|
"@types/pluralize": "^0.0.29",
|
|
36
|
+
"@types/stream-json": "^1.7.7",
|
|
31
37
|
"@typescript-eslint/eslint-plugin": "^4.8.2",
|
|
32
38
|
"@typescript-eslint/parser": "^4.8.2",
|
|
39
|
+
"axios-mock-adapter": "^1.22.0",
|
|
40
|
+
"esbuild": "^0.20.1",
|
|
33
41
|
"eslint": "^7.14.0",
|
|
34
|
-
"jest": "^29.0
|
|
42
|
+
"jest": "^29.7.0",
|
|
43
|
+
"lodash": "^4.17.21",
|
|
35
44
|
"pluralize": "^8.0.0",
|
|
36
|
-
"
|
|
45
|
+
"protobufjs": "^7.2.6",
|
|
46
|
+
"ts-jest": "^29.1.2",
|
|
37
47
|
"tsx": "^4.19.3",
|
|
38
48
|
"typescript": "^5.5.4"
|
|
39
49
|
},
|
package/CHANGELOG.md
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
### Upcoming Breaking Changes
|
|
4
|
-
|
|
5
|
-
From v20 onwards this library will use the REST api for report, reportStream, search and searchStream. This will result in minor breaking changes to reporting calls:
|
|
6
|
-
|
|
7
|
-
- Fields with the enum value `0` will now be `undefined` instead
|
|
8
|
-
- Array-fields (such as `final_urls`) with the value `[]` will now be `undefined` instead
|
|
9
|
-
|
|
10
|
-
While these changes are inconvenient, the performance of the REST api is significantly better than the gRPC api, particularly for responses with many rows.
|
|
11
|
-
|
|
12
|
-
To prepare for this change, we recommend you use the install the `19.0.0-rest-beta` version of this library and test your application with it.
|
|
13
|
-
|
|
14
|
-
### 19.0.2
|
|
15
|
-
|
|
16
|
-
- Fix issue with reportCount() not giving the correct total results count.
|
|
17
|
-
|
|
18
|
-
## 19.0.1
|
|
19
|
-
|
|
20
|
-
- Fix issue with type interface for search_settings not showing any valid fields.
|
|
21
|
-
|
|
22
|
-
## 19.0.0
|
|
23
|
-
|
|
24
|
-
### Version Upgrade
|
|
25
|
-
|
|
26
|
-
- Upgraded google-ads-api version to v19. Refer to Google ads release notes [here](https://developers.google.com/google-ads/api/docs/release-notes) for changes.
|
|
27
|
-
|
|
28
|
-
### Library Changes
|
|
29
|
-
|
|
30
|
-
- We currently do not support `return_total_results_count` on search_settings for SearchGoogleAdsRequest. Please use `reportCount()` instead. This has been reflected in the `RequestOptions` type:
|
|
31
|
-
|
|
32
|
-
```ts
|
|
33
|
-
export type RequestOptions = Omit<
|
|
34
|
-
services.ISearchGoogleAdsRequest,
|
|
35
|
-
"customer_id" | "query" | "search_settings"
|
|
36
|
-
> & {
|
|
37
|
-
search_settings?: Omit<
|
|
38
|
-
services.ISearchSettings,
|
|
39
|
-
"return_total_results_count"
|
|
40
|
-
>;
|
|
41
|
-
};
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
For more information please see the `SearchSettings` reference on the Google document [here](https://developers.google.com/google-ads/api/reference/rpc/v19/SearchSettings).
|