google-ads-api 24.1.0 → 25.1.0-beta.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.
Files changed (74) hide show
  1. package/README.md +9 -1
  2. package/build/{src → cjs}/client.d.ts +6 -4
  3. package/build/{src → cjs}/client.js +4 -4
  4. package/build/{src → cjs}/customer.d.ts +5 -5
  5. package/build/{src → cjs}/customer.js +24 -20
  6. package/build/{src → cjs}/hooks.d.ts +2 -2
  7. package/build/cjs/index.d.ts +9 -0
  8. package/build/{src → cjs}/index.js +22 -20
  9. package/build/{src → cjs}/parser.d.ts +2 -2
  10. package/build/{src → cjs}/parser.js +5 -5
  11. package/build/{src → cjs}/parserRest.js +7 -7
  12. package/build/{src → cjs}/protos/autogen/enums.d.ts +932 -433
  13. package/build/{src → cjs}/protos/autogen/enums.js +949 -430
  14. package/build/cjs/protos/autogen/fields.d.ts +1191 -0
  15. package/build/cjs/protos/autogen/fields.js +681 -0
  16. package/build/{src → cjs}/protos/autogen/resourceNames.d.ts +74 -15
  17. package/build/{src → cjs}/protos/autogen/resourceNames.js +90 -19
  18. package/build/{src → cjs}/protos/autogen/serviceFactory.d.ts +206 -215
  19. package/build/{src → cjs}/protos/autogen/serviceFactory.js +321 -392
  20. package/build/cjs/protos/index.d.ts +14 -0
  21. package/build/{src → cjs}/protos/index.js +12 -12
  22. package/build/{src → cjs}/query.d.ts +2 -2
  23. package/build/{src → cjs}/query.js +5 -5
  24. package/build/{src → cjs}/service.d.ts +5 -5
  25. package/build/cjs/service.js +263 -0
  26. package/build/{src → cjs}/types.d.ts +1 -1
  27. package/build/{src → cjs}/utils.d.ts +1 -1
  28. package/build/{src → cjs}/utils.js +2 -2
  29. package/build/cjs/version.d.ts +1 -0
  30. package/build/{src → cjs}/version.js +1 -1
  31. package/build/esm/client.d.ts +19 -0
  32. package/build/esm/client.js +40 -0
  33. package/build/esm/customer.d.ts +71 -0
  34. package/build/esm/customer.js +502 -0
  35. package/build/esm/hooks.d.ts +160 -0
  36. package/build/esm/hooks.js +1 -0
  37. package/build/esm/index.d.ts +9 -0
  38. package/build/esm/index.js +10 -0
  39. package/build/esm/package.json +1 -0
  40. package/build/esm/parser.d.ts +21 -0
  41. package/build/esm/parser.js +113 -0
  42. package/build/esm/parserRest.d.ts +1 -0
  43. package/build/esm/parserRest.js +112 -0
  44. package/build/esm/protos/autogen/enums.d.ts +6002 -0
  45. package/build/esm/protos/autogen/enums.js +6401 -0
  46. package/build/esm/protos/autogen/fields.d.ts +1191 -0
  47. package/build/esm/protos/autogen/fields.js +678 -0
  48. package/build/esm/protos/autogen/resourceNames.d.ts +1668 -0
  49. package/build/esm/protos/autogen/resourceNames.js +1859 -0
  50. package/build/esm/protos/autogen/serviceFactory.d.ts +1825 -0
  51. package/build/esm/protos/autogen/serviceFactory.js +18795 -0
  52. package/build/esm/protos/index.d.ts +14 -0
  53. package/build/esm/protos/index.js +19 -0
  54. package/build/esm/query.d.ts +62 -0
  55. package/build/esm/query.js +304 -0
  56. package/build/esm/service.d.ts +47 -0
  57. package/build/{src → esm}/service.js +42 -41
  58. package/build/esm/types.d.ts +75 -0
  59. package/build/esm/types.js +14 -0
  60. package/build/esm/utils.d.ts +49 -0
  61. package/build/esm/utils.js +108 -0
  62. package/build/esm/version.d.ts +1 -0
  63. package/build/esm/version.js +1 -0
  64. package/package.json +54 -13
  65. package/build/src/index.d.ts +0 -8
  66. package/build/src/protos/autogen/fields.d.ts +0 -1122
  67. package/build/src/protos/autogen/fields.js +0 -644
  68. package/build/src/protos/index.d.ts +0 -14
  69. package/build/src/testUtils.d.ts +0 -107
  70. package/build/src/testUtils.js +0 -333
  71. package/build/src/version.d.ts +0 -1
  72. /package/build/{src → cjs}/hooks.js +0 -0
  73. /package/build/{src → cjs}/parserRest.d.ts +0 -0
  74. /package/build/{src → cjs}/types.js +0 -0
@@ -0,0 +1,14 @@
1
+ import allProtos, { protos } from "google-ads-node";
2
+ export declare const VERSION: "v25";
3
+ export import common = protos.google.ads.googleads.v25.common;
4
+ export import errors = protos.google.ads.googleads.v25.errors;
5
+ export import resources = protos.google.ads.googleads.v25.resources;
6
+ export import services = protos.google.ads.googleads.v25.services;
7
+ export import internalEnums = protos.google.ads.googleads.v25.enums;
8
+ export { enums } from "./autogen/enums.js";
9
+ export { fields, fieldDataTypes } from "./autogen/fields.js";
10
+ export { GoogleAdsServiceClient } from "google-ads-node";
11
+ export type AllServices = Omit<typeof allProtos, typeof VERSION>;
12
+ export type ServiceName = keyof Omit<typeof allProtos, typeof VERSION>;
13
+ export import protobuf = protos.google.protobuf;
14
+ export import longrunning = protos.google.longrunning;
@@ -0,0 +1,19 @@
1
+ import { protos } from "google-ads-node";
2
+ import { googleAdsVersion } from "../version.js";
3
+ // "as vN" is required to avoid type issues later on
4
+ export const VERSION = googleAdsVersion;
5
+ // -- Expose the googleads generated types --
6
+ // The namespace path is shortened for ease of use
7
+ export var common = protos.google.ads.googleads.v25.common;
8
+ export var errors = protos.google.ads.googleads.v25.errors;
9
+ export var resources = protos.google.ads.googleads.v25.resources;
10
+ export var services = protos.google.ads.googleads.v25.services;
11
+ // We compile enums ourselves, the Google ones should be used internally only
12
+ export var internalEnums = protos.google.ads.googleads.v25.enums;
13
+ export { enums } from "./autogen/enums.js";
14
+ export { fields, fieldDataTypes } from "./autogen/fields.js";
15
+ // Common service used for report/query methods
16
+ export { GoogleAdsServiceClient } from "google-ads-node";
17
+ // -- Expose some google protobuf helpers --
18
+ export var protobuf = protos.google.protobuf;
19
+ export var longrunning = protos.google.longrunning;
@@ -0,0 +1,62 @@
1
+ import { fields } from "./protos/index.js";
2
+ import { ConstraintKey, ConstraintOperation, ConstraintValue, ReportOptions, RequestOptions, RequestOptionsWithTotalResults, SortOrder } from "./types.js";
3
+ declare enum QueryKeywords {
4
+ SELECT = "SELECT",
5
+ FROM = "FROM",
6
+ WHERE = "WHERE",
7
+ ORDER_BY = "ORDER BY",
8
+ LIMIT = "LIMIT",
9
+ PARAMETERS = "PARAMETERS",
10
+ AND = "AND",
11
+ OR = "OR"
12
+ }
13
+ type ParsedConstraintValue = string | number | boolean;
14
+ type ConstraintString = `${string} ${ConstraintOperation} ${ParsedConstraintValue}`;
15
+ type SelectClause = `${QueryKeywords.SELECT} ${string}`;
16
+ type FromClause = ` ${QueryKeywords.FROM} ${fields.Resource}`;
17
+ type WhereClause = ` ${QueryKeywords.WHERE} ${string}` | ``;
18
+ export type OrderClause = ` ${QueryKeywords.ORDER_BY} ${string} ${SortOrder}` | ` ${QueryKeywords.ORDER_BY} ${string}` | ``;
19
+ type LimitClause = ` ${QueryKeywords.LIMIT} ${number}` | ``;
20
+ type ParametersClause = ` ${QueryKeywords.PARAMETERS} ${string}` | ``;
21
+ type Query = `${SelectClause}${FromClause}${WhereClause}${OrderClause}${LimitClause}${ParametersClause}`;
22
+ export declare const QueryError: {
23
+ INVALID_CONSTRAINTS_FORMAT: string;
24
+ INVALID_CONSTRAINT_KEY: string;
25
+ INVALID_CONSTRAINT_VALUE: (key: ConstraintKey, val: ConstraintValue) => string;
26
+ INVALID_CONSTRAINT_OBJECT_FORMAT: string;
27
+ INVALID_DATE_CONSTANT_TYPE: (dateConstant: ReportOptions["date_constant"]) => string;
28
+ INVALID_FROM_DATE_TYPE: (fromDate: ReportOptions["from_date"]) => string;
29
+ INVALID_TO_DATE_TYPE: (toDate: ReportOptions["to_date"]) => string;
30
+ INVALID_LIMIT: string;
31
+ INVALID_PARAMETERS: string;
32
+ INVALID_ORDER: string;
33
+ INVALID_ORDERLY: string;
34
+ INVALID_ORDERBY: string;
35
+ INVALID_SORT_ORDER: string;
36
+ MISSING_FIELDS: string;
37
+ MISSING_FROM_DATE: string;
38
+ UNDEFINED_ENTITY: string;
39
+ };
40
+ export declare function buildSelectClause(attributes: ReportOptions["attributes"], metrics: ReportOptions["metrics"], segments: ReportOptions["segments"]): SelectClause;
41
+ export declare function buildFromClause(entity: ReportOptions["entity"]): FromClause;
42
+ export declare function validateConstraintKeyAndValue(key: ConstraintKey, op: ConstraintOperation, val: ConstraintValue): {
43
+ op: ConstraintOperation;
44
+ val: ParsedConstraintValue;
45
+ };
46
+ export declare function convertNumericEnumToString(key: ConstraintKey, val: ParsedConstraintValue): ParsedConstraintValue;
47
+ export declare function extractConstraintConditions(constraints: Readonly<ReportOptions["constraints"]>): ConstraintString[];
48
+ export declare function extractDateConstantConditions(dateConstant: ReportOptions["date_constant"]): ConstraintString[];
49
+ export declare function extractDateConditions(fromDate: ReportOptions["from_date"], toDate: ReportOptions["to_date"]): ConstraintString[];
50
+ export declare function buildWhereClause(constraints: Readonly<ReportOptions["constraints"]>, dateConstant: Readonly<ReportOptions["date_constant"]>, fromDate: Readonly<ReportOptions["from_date"]>, toDate: Readonly<ReportOptions["to_date"]>): WhereClause;
51
+ export declare function buildLimitClause(limit: ReportOptions["limit"]): LimitClause;
52
+ export declare function buildParametersClause(parameters: Readonly<ReportOptions["parameters"]>): ParametersClause;
53
+ export declare function completeOrderly(orderly: string, entity: ReportOptions["entity"]): string;
54
+ export declare function buildOrderClauseOld(orderBy: Readonly<ReportOptions["order_by"]>, sortOrder: Readonly<ReportOptions["sort_order"]>, entity: Readonly<ReportOptions["entity"]>): OrderClause;
55
+ export declare function buildOrderClauseNew(order: Readonly<Required<ReportOptions["order"]>>, entity: Readonly<ReportOptions["entity"]>): OrderClause;
56
+ export declare function buildOrderClause(order: Readonly<ReportOptions["order"]>, orderBy: Readonly<ReportOptions["order_by"]>, sortOrder: Readonly<ReportOptions["sort_order"]>, entity: Readonly<ReportOptions["entity"]>): OrderClause;
57
+ export declare function buildRequestOptions(reportOptions: Readonly<ReportOptions>): RequestOptions;
58
+ export declare function buildQuery(reportOptions: Readonly<ReportOptions>): {
59
+ gaqlQuery: Query;
60
+ requestOptions: RequestOptionsWithTotalResults;
61
+ };
62
+ export {};
@@ -0,0 +1,304 @@
1
+ import { enums, fields } from "./protos/index.js";
2
+ import { dateConstants, } from "./types.js";
3
+ var QueryKeywords;
4
+ (function (QueryKeywords) {
5
+ QueryKeywords["SELECT"] = "SELECT";
6
+ QueryKeywords["FROM"] = "FROM";
7
+ QueryKeywords["WHERE"] = "WHERE";
8
+ QueryKeywords["ORDER_BY"] = "ORDER BY";
9
+ QueryKeywords["LIMIT"] = "LIMIT";
10
+ QueryKeywords["PARAMETERS"] = "PARAMETERS";
11
+ QueryKeywords["AND"] = "AND";
12
+ QueryKeywords["OR"] = "OR";
13
+ })(QueryKeywords || (QueryKeywords = {}));
14
+ export const QueryError = {
15
+ INVALID_CONSTRAINTS_FORMAT: "Constraints must be an array of objects or a singular object.",
16
+ INVALID_CONSTRAINT_KEY: "A constraint key must have a string value.",
17
+ INVALID_CONSTRAINT_VALUE: (key, val) =>
18
+ // @ts-ignore
19
+ `The value of the constraint ${key} must be a string, number, boolean, or an array of these types. Here, typeof ${key} is ${typeof val}.`,
20
+ INVALID_CONSTRAINT_OBJECT_FORMAT: "Must specify { key, op, val } or { key: value } when using object-style constraints.",
21
+ INVALID_DATE_CONSTANT_TYPE: (dateConstant) => `Date constant must be a string. Here, typeof date constant is ${typeof dateConstant}`,
22
+ INVALID_FROM_DATE_TYPE: (fromDate) => `From date must be a string. Here, typeof from date is ${typeof fromDate}`,
23
+ INVALID_TO_DATE_TYPE: (toDate) => `To date must be a string. Here, typeof to date is ${typeof toDate}`,
24
+ INVALID_LIMIT: "Limit must be a positive integer.",
25
+ INVALID_PARAMETERS: "Parameters must be a string.",
26
+ INVALID_ORDER: "Order must be an array.",
27
+ INVALID_ORDERLY: "OrderBy arrays must only contain strings.",
28
+ INVALID_ORDERBY: "OrderBy must be a string or an array of strings.",
29
+ INVALID_SORT_ORDER: `Sort order must be "ASC" or "DESC".`,
30
+ MISSING_FIELDS: 'Must specify at least one field in ("attributes","metrics","segments").',
31
+ MISSING_FROM_DATE: 'Expected start date range is missing - "from_date".',
32
+ UNDEFINED_ENTITY: "The entity of the query must be defined.",
33
+ };
34
+ export function buildSelectClause(attributes, metrics, segments) {
35
+ if (!attributes?.length && !metrics?.length && !segments?.length) {
36
+ throw new Error(QueryError.MISSING_FIELDS);
37
+ }
38
+ const selections = [
39
+ ...(attributes || []),
40
+ ...(metrics || []),
41
+ ...(segments || []),
42
+ ].join(", ");
43
+ return `${QueryKeywords.SELECT} ${selections}`;
44
+ }
45
+ export function buildFromClause(entity) {
46
+ if (typeof entity === "undefined") {
47
+ throw new Error(QueryError.UNDEFINED_ENTITY);
48
+ }
49
+ return ` ${QueryKeywords.FROM} ${entity}`;
50
+ }
51
+ function formatGaqlString(val) {
52
+ const len = val.length;
53
+ const startsWithSingle = val.startsWith("'");
54
+ const endsWithSingle = val.endsWith("'");
55
+ const startsWithDouble = val.startsWith('"');
56
+ const endsWithDouble = val.endsWith('"');
57
+ // Returns the original string if it seems correctly quoted already.
58
+ if (len >= 2) {
59
+ if (startsWithSingle && endsWithSingle && !val.slice(1, -1).includes("'")) {
60
+ return val;
61
+ }
62
+ if (startsWithDouble && endsWithDouble && !val.slice(1, -1).includes('"')) {
63
+ return val;
64
+ }
65
+ }
66
+ // Always use double quotes and escape internal double quotes and backslashes
67
+ if (val.includes('"') || val.includes("\\")) {
68
+ const escapedVal = val.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); // Escape backslashes first, then double quotes
69
+ return `"${escapedVal}"`;
70
+ }
71
+ else {
72
+ // No escaping needed, just wrap in double quotes
73
+ return `"${val}"`;
74
+ }
75
+ }
76
+ export function validateConstraintKeyAndValue(key, op, val) {
77
+ if (typeof val === "number" || typeof val === "boolean") {
78
+ return { op: "=", val: convertNumericEnumToString(key, val) };
79
+ }
80
+ if (typeof val === "string") {
81
+ if (dateConstants.includes(val)) {
82
+ return { op, val };
83
+ }
84
+ return { op: "=", val: formatGaqlString(val) };
85
+ }
86
+ if (Array.isArray(val)) {
87
+ const stringifiedValue = val
88
+ .map((v) => {
89
+ if (typeof v === "string") {
90
+ return formatGaqlString(v);
91
+ }
92
+ else {
93
+ return convertNumericEnumToString(key, v);
94
+ }
95
+ })
96
+ .join(`, `);
97
+ return { op: "IN", val: `(${stringifiedValue})` };
98
+ }
99
+ throw new Error(QueryError.INVALID_CONSTRAINT_VALUE(key, val));
100
+ }
101
+ export function convertNumericEnumToString(key, val) {
102
+ // @ts-expect-error key does not always match an enum field
103
+ if (fields.enumFields[key] && typeof val === "number") {
104
+ // @ts-expect-error typescript doesn't like accessing items in a namespace with a string
105
+ const enumStringValue = enums[fields.enumFields[key]][val]; // e.g. enums['CampaignStatus'][2] = "ENABLED"
106
+ if (enumStringValue) {
107
+ return `"${enumStringValue}"`;
108
+ }
109
+ }
110
+ return val;
111
+ }
112
+ export function extractConstraintConditions(constraints) {
113
+ if (typeof constraints === "undefined") {
114
+ return [];
115
+ }
116
+ else if (Array.isArray(constraints)) {
117
+ return constraints.map((con) => {
118
+ if (typeof con === "object" && !Array.isArray(con) && con !== null) {
119
+ // @ts-ignore
120
+ if (con.key && con.op && typeof con.val !== "undefined") {
121
+ const { key, op, val } = con;
122
+ if (typeof key !== "string") {
123
+ throw new Error(QueryError.INVALID_CONSTRAINT_KEY);
124
+ }
125
+ const validatedValue = validateConstraintKeyAndValue(key, op, val);
126
+ // @ts-ignore
127
+ return `${key} ${op} ${validatedValue.val}`;
128
+ }
129
+ else if (Object.keys(con).length === 1) {
130
+ const [[key, val]] = Object.entries(con);
131
+ const validatedValue = validateConstraintKeyAndValue(key, "=", val);
132
+ return `${key} ${validatedValue.op} ${validatedValue.val}`;
133
+ }
134
+ else {
135
+ throw new Error(QueryError.INVALID_CONSTRAINT_OBJECT_FORMAT);
136
+ }
137
+ }
138
+ else if (typeof con === "string") {
139
+ return con;
140
+ }
141
+ else {
142
+ throw new Error(QueryError.INVALID_CONSTRAINT_OBJECT_FORMAT);
143
+ }
144
+ });
145
+ }
146
+ else if (typeof constraints === "object" && constraints !== null) {
147
+ return Object.entries(constraints).map(([key, val]) => {
148
+ const validatedValue = validateConstraintKeyAndValue(key, "=", val);
149
+ return `${key} ${validatedValue.op} ${validatedValue.val}`;
150
+ });
151
+ }
152
+ else {
153
+ throw new Error(QueryError.INVALID_CONSTRAINTS_FORMAT);
154
+ }
155
+ }
156
+ export function extractDateConstantConditions(dateConstant) {
157
+ if (typeof dateConstant === "undefined") {
158
+ return [];
159
+ }
160
+ else if (typeof dateConstant !== "string") {
161
+ throw new Error(QueryError.INVALID_DATE_CONSTANT_TYPE(dateConstant));
162
+ }
163
+ return [`segments.date DURING ${dateConstant}`];
164
+ }
165
+ export function extractDateConditions(fromDate, toDate) {
166
+ if (typeof fromDate === "undefined" && typeof toDate === "undefined") {
167
+ return [];
168
+ }
169
+ if (typeof fromDate === "undefined" && typeof toDate !== "undefined") {
170
+ throw new Error(QueryError.MISSING_FROM_DATE);
171
+ }
172
+ if (typeof fromDate !== "undefined" && typeof toDate === "undefined") {
173
+ const d = new Date();
174
+ toDate = `${d.getFullYear()}-${("0" + (d.getMonth() + 1)).slice(-2)}-${("0" + d.getDate()).slice(-2)}`;
175
+ }
176
+ if (typeof fromDate !== "string") {
177
+ throw new Error(QueryError.INVALID_FROM_DATE_TYPE(fromDate));
178
+ }
179
+ if (typeof toDate !== "string") {
180
+ throw new Error(QueryError.INVALID_TO_DATE_TYPE(toDate));
181
+ }
182
+ return [
183
+ `segments.date >= "${fromDate}"`,
184
+ `segments.date <= "${toDate}"`,
185
+ ];
186
+ }
187
+ export function buildWhereClause(constraints, dateConstant, fromDate, toDate) {
188
+ const constraintClauses = extractConstraintConditions(constraints);
189
+ const dateConstantClauses = extractDateConstantConditions(dateConstant);
190
+ const dateClauses = extractDateConditions(fromDate, toDate);
191
+ const whereClauses = [
192
+ ...constraintClauses,
193
+ ...dateConstantClauses,
194
+ ...dateClauses,
195
+ ].join(` ${QueryKeywords.AND} `);
196
+ return whereClauses.length
197
+ ? ` ${QueryKeywords.WHERE} ${whereClauses}`
198
+ : ``;
199
+ }
200
+ export function buildLimitClause(limit) {
201
+ if (typeof limit === "undefined") {
202
+ return ``;
203
+ }
204
+ if (typeof limit !== "number" || limit < 1 || !Number.isInteger(limit)) {
205
+ throw new Error(QueryError.INVALID_LIMIT);
206
+ }
207
+ return ` ${QueryKeywords.LIMIT} ${limit}`;
208
+ }
209
+ export function buildParametersClause(parameters) {
210
+ if (typeof parameters === "undefined") {
211
+ return ``;
212
+ }
213
+ if (typeof parameters !== "string") {
214
+ throw new Error(QueryError.INVALID_PARAMETERS);
215
+ }
216
+ return ` ${QueryKeywords.PARAMETERS} ${parameters}`;
217
+ }
218
+ export function completeOrderly(orderly, entity) {
219
+ if (!orderly.length) {
220
+ throw new Error(QueryError.INVALID_ORDERLY);
221
+ }
222
+ else if (new RegExp(/^[^.\s]+(\.[^.\s]+)+$/g).test(orderly)) {
223
+ // text containing full stops
224
+ return orderly;
225
+ }
226
+ else if (new RegExp(/^[^.\s]+$/g).test(orderly)) {
227
+ // text without a full stop (e.g. resource_name)
228
+ return `${entity}.${orderly}`;
229
+ }
230
+ else {
231
+ throw new Error(QueryError.INVALID_ORDERLY);
232
+ }
233
+ }
234
+ export function buildOrderClauseOld(orderBy, sortOrder, entity) {
235
+ if (typeof orderBy === "undefined") {
236
+ return ``;
237
+ }
238
+ else if (typeof sortOrder === "undefined") {
239
+ sortOrder = "DESC";
240
+ }
241
+ else if (sortOrder !== "ASC" && sortOrder !== "DESC") {
242
+ throw new Error(QueryError.INVALID_SORT_ORDER);
243
+ }
244
+ if (Array.isArray(orderBy)) {
245
+ const orders = orderBy
246
+ .map((orderly) => {
247
+ if (typeof orderly !== "string") {
248
+ throw new Error(QueryError.INVALID_ORDERLY);
249
+ }
250
+ else {
251
+ return completeOrderly(orderly, entity);
252
+ }
253
+ })
254
+ .join(", ");
255
+ return ` ${QueryKeywords.ORDER_BY} ${orders} ${sortOrder}`;
256
+ }
257
+ else if (typeof orderBy === "string") {
258
+ return ` ${QueryKeywords.ORDER_BY} ${completeOrderly(orderBy, entity)} ${sortOrder}`;
259
+ }
260
+ else {
261
+ throw new Error(QueryError.INVALID_ORDERBY);
262
+ }
263
+ }
264
+ export function buildOrderClauseNew(order, entity) {
265
+ if (!order || !Array.isArray(order)) {
266
+ throw new Error(QueryError.INVALID_ORDER);
267
+ }
268
+ if (!order.length) {
269
+ return "";
270
+ }
271
+ const orders = order
272
+ .map((o) => {
273
+ const orderly = completeOrderly(o.field, entity);
274
+ const sortOrder = o.sort_order ? o.sort_order : "DESC";
275
+ return `${orderly} ${sortOrder}`;
276
+ })
277
+ .join(", ");
278
+ return ` ${QueryKeywords.ORDER_BY} ${orders}`;
279
+ }
280
+ export function buildOrderClause(order, orderBy, sortOrder, entity) {
281
+ if (order) {
282
+ return buildOrderClauseNew(order, entity);
283
+ }
284
+ else {
285
+ return buildOrderClauseOld(orderBy, sortOrder, entity);
286
+ }
287
+ }
288
+ export function buildRequestOptions(reportOptions) {
289
+ const { page_size, page_token, validate_only, search_settings } = reportOptions;
290
+ return { page_size, page_token, validate_only, search_settings };
291
+ }
292
+ export function buildQuery(reportOptions) {
293
+ const SELECT = buildSelectClause(reportOptions.attributes, reportOptions.metrics, reportOptions.segments);
294
+ const FROM = buildFromClause(reportOptions.entity);
295
+ const WHERE = buildWhereClause(reportOptions.constraints, reportOptions.date_constant, reportOptions.from_date, reportOptions.to_date);
296
+ const ORDER = buildOrderClause(reportOptions.order, reportOptions.order_by, reportOptions.sort_order, reportOptions.entity);
297
+ const LIMIT = buildLimitClause(reportOptions.limit);
298
+ const PARAMETERS = buildParametersClause(reportOptions.parameters);
299
+ const requestOptions = buildRequestOptions(reportOptions);
300
+ return {
301
+ gaqlQuery: `${SELECT}${FROM}${WHERE}${ORDER}${LIMIT}${PARAMETERS}`,
302
+ requestOptions,
303
+ };
304
+ }
@@ -0,0 +1,47 @@
1
+ import { ClientOptions } from "./client.js";
2
+ import { AllServices, errors, GoogleAdsServiceClient, ServiceName, services } from "./protos/index.js";
3
+ import { CustomerOptions, CustomerCredentials, RequestOptions, MutateOperation, MutateOptions } from "./types.js";
4
+ import { Hooks } from "./hooks.js";
5
+ import TTLCache from "@isaacs/ttlcache";
6
+ export declare const FAILURE_KEY = "google.ads.googleads.v25.errors.googleadsfailure-bin";
7
+ export interface CallHeaders {
8
+ "developer-token": string;
9
+ "login-customer-id"?: string;
10
+ "linked-customer-id"?: string;
11
+ }
12
+ export declare function disposeService(service: {
13
+ close: () => Promise<void>;
14
+ }): void;
15
+ export declare const serviceCache: TTLCache<unknown, {
16
+ close: () => Promise<void>;
17
+ }>;
18
+ export declare class Service {
19
+ protected readonly clientOptions: ClientOptions;
20
+ protected readonly customerOptions: CustomerOptions;
21
+ protected readonly hooks: Hooks;
22
+ constructor(clientOptions: ClientOptions, customerOptions: CustomerOptions, hooks?: Hooks);
23
+ get credentials(): CustomerCredentials;
24
+ protected get callHeaders(): CallHeaders;
25
+ private getCredentials;
26
+ getAccessToken(): Promise<string>;
27
+ protected loadService<T = AllServices>(service: ServiceName, options?: {
28
+ skipCache?: boolean;
29
+ }): T;
30
+ protected getGoogleAdsError(error: Error): errors.GoogleAdsFailure | Error;
31
+ private decodeGoogleAdsFailureBuffer;
32
+ protected decodePartialFailureError<T>(response: T): T;
33
+ protected buildSearchRequestAndService(gaql: string, options?: RequestOptions): {
34
+ service: GoogleAdsServiceClient;
35
+ request: services.SearchGoogleAdsRequest;
36
+ };
37
+ protected buildSearchStreamRequestAndService(gaql: string, options?: RequestOptions): {
38
+ service: GoogleAdsServiceClient;
39
+ request: services.SearchGoogleAdsStreamRequest;
40
+ };
41
+ protected buildMutationRequestAndService<T>(mutations: MutateOperation<T>[], options?: MutateOptions): {
42
+ service: GoogleAdsServiceClient;
43
+ request: services.MutateGoogleAdsRequest;
44
+ };
45
+ protected buildOperations<Op, Ent>(type: "create" | "update" | "remove", entities: Ent[], message?: Ent): Op[];
46
+ protected buildRequest<Op, Req, Options>(operations: Op[], options?: Options): Req;
47
+ }
@@ -1,37 +1,31 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Service = exports.serviceCache = exports.FAILURE_KEY = void 0;
7
- exports.disposeService = disposeService;
8
- const google_gax_1 = require("google-gax");
9
- const google_auth_library_1 = require("google-auth-library");
10
- const protos_1 = require("./protos");
11
- const utils_1 = require("./utils");
12
- const version_1 = require("./version");
13
- const ttlcache_1 = __importDefault(require("@isaacs/ttlcache"));
1
+ import { grpc } from "google-gax";
2
+ import * as googleAdsNode from "google-ads-node";
3
+ import { UserRefreshClient, OAuth2Client } from "google-auth-library";
4
+ import { errors, services, } from "./protos/index.js";
5
+ import { getFieldMask, toSnakeCase } from "./utils.js";
6
+ import { googleAdsVersion } from "./version.js";
7
+ import TTLCache from "@isaacs/ttlcache";
14
8
  // Make sure to update this version number when upgrading
15
- exports.FAILURE_KEY = `google.ads.googleads.${version_1.googleAdsVersion}.errors.googleadsfailure-bin`;
9
+ export const FAILURE_KEY = `google.ads.googleads.${googleAdsVersion}.errors.googleadsfailure-bin`;
16
10
  // Close connections when services are removed from the cache
17
- function disposeService(service) {
11
+ export function disposeService(service) {
18
12
  Promise.resolve()
19
13
  .then(() => service.close())
20
14
  .catch(() => null);
21
15
  }
22
16
  // A global service cache to avoid re-initialising services
23
- exports.serviceCache = new ttlcache_1.default({
17
+ export const serviceCache = new TTLCache({
24
18
  max: 1_000,
25
19
  ttl: 10 * 60 * 1000, // 10 minutes
26
20
  checkAgeOnGet: true,
27
21
  dispose: disposeService,
28
22
  });
29
23
  // A global access token cache used by REST calls. Issued tokens expire after 1 hour, so we cache them for 50 minutes.
30
- const accessTokenCache = new ttlcache_1.default({
24
+ const accessTokenCache = new TTLCache({
31
25
  max: 100_000,
32
26
  ttl: 50 * 60 * 1000, // 50 minutes
33
27
  });
34
- class Service {
28
+ export class Service {
35
29
  clientOptions;
36
30
  customerOptions;
37
31
  hooks;
@@ -63,9 +57,15 @@ class Service {
63
57
  }
64
58
  // Used only by gRPC calls
65
59
  getCredentials() {
66
- const sslCreds = google_gax_1.grpc.credentials.createSsl();
67
- const authClient = new google_auth_library_1.UserRefreshClient(this.clientOptions.client_id, this.clientOptions.client_secret, this.customerOptions.refresh_token);
68
- const credentials = google_gax_1.grpc.credentials.combineChannelCredentials(sslCreds, google_gax_1.grpc.credentials.createFromGoogleCredential(authClient));
60
+ const sslCreds = grpc.credentials.createSsl();
61
+ const authClient = new UserRefreshClient({
62
+ clientId: this.clientOptions.client_id,
63
+ clientSecret: this.clientOptions.client_secret,
64
+ refreshToken: this.customerOptions.refresh_token,
65
+ });
66
+ const credentials = grpc.credentials.combineChannelCredentials(sslCreds, grpc.credentials.createFromGoogleCredential({
67
+ getRequestHeaders: async (url) => Object.fromEntries(await authClient.getRequestHeaders(url)),
68
+ }));
69
69
  return credentials;
70
70
  }
71
71
  // Used only by REST calls
@@ -74,7 +74,10 @@ class Service {
74
74
  if (cachedToken) {
75
75
  return cachedToken;
76
76
  }
77
- const oAuth2Client = new google_auth_library_1.OAuth2Client(this.clientOptions.client_id, this.clientOptions.client_secret);
77
+ const oAuth2Client = new OAuth2Client({
78
+ clientId: this.clientOptions.client_id,
79
+ clientSecret: this.clientOptions.client_secret,
80
+ });
78
81
  oAuth2Client.setCredentials({
79
82
  refresh_token: this.customerOptions.refresh_token,
80
83
  });
@@ -86,38 +89,37 @@ class Service {
86
89
  return token;
87
90
  }
88
91
  loadService(service, options) {
89
- const serviceCacheKey = `${service}_${this.clientOptions.client_id}_${this.customerOptions.refresh_token}`;
92
+ const serviceCacheKey = `${service}_${this.clientOptions.client_id}_${this.customerOptions.refresh_token}_${JSON.stringify(this.clientOptions.grpc_channel_options ?? null)}`;
90
93
  if (!options?.skipCache) {
91
- const cachedService = exports.serviceCache.get(serviceCacheKey);
94
+ const cachedService = serviceCache.get(serviceCacheKey);
92
95
  if (cachedService) {
93
96
  return cachedService;
94
97
  }
95
98
  }
96
- // eslint-disable-next-line @typescript-eslint/no-var-requires
97
- const { [service]: protoService } = require("google-ads-node");
99
+ const protoService = googleAdsNode[service];
98
100
  if (typeof protoService === "undefined") {
99
101
  throw new Error(`Service "${String(service)}" could not be found`);
100
102
  }
101
103
  // Initialising services can take a few ms, so we cache when possible.
102
104
  const client = new protoService({
105
+ ...this.clientOptions.grpc_channel_options,
103
106
  sslCreds: this.getCredentials(),
107
+ universeDomain: "googleapis.com",
104
108
  });
105
109
  if (!options?.skipCache) {
106
- exports.serviceCache.set(serviceCacheKey, client);
110
+ serviceCache.set(serviceCacheKey, client);
107
111
  }
108
112
  return client;
109
113
  }
110
114
  getGoogleAdsError(error) {
111
- // @ts-expect-error No type exists for GA query error
112
- if (typeof error?.metadata?.internalRepr.get(exports.FAILURE_KEY) === "undefined") {
115
+ const trailer = error?.metadata?.internalRepr?.get?.(FAILURE_KEY);
116
+ if (typeof trailer?.[0] === "undefined") {
113
117
  return error;
114
118
  }
115
- // @ts-expect-error No type exists for GA query error
116
- const [buffer] = error.metadata.internalRepr.get(exports.FAILURE_KEY);
117
- return this.decodeGoogleAdsFailureBuffer(buffer);
119
+ return this.decodeGoogleAdsFailureBuffer(trailer[0]);
118
120
  }
119
121
  decodeGoogleAdsFailureBuffer(buffer) {
120
- const googleAdsFailure = protos_1.errors.GoogleAdsFailure.decode(buffer);
122
+ const googleAdsFailure = errors.GoogleAdsFailure.decode(buffer);
121
123
  return googleAdsFailure;
122
124
  }
123
125
  decodePartialFailureError(response) {
@@ -138,7 +140,7 @@ class Service {
138
140
  }
139
141
  buildSearchRequestAndService(gaql, options) {
140
142
  const service = this.loadService("GoogleAdsServiceClient");
141
- const request = new protos_1.services.SearchGoogleAdsRequest({
143
+ const request = new services.SearchGoogleAdsRequest({
142
144
  customer_id: this.customerOptions.customer_id,
143
145
  query: gaql,
144
146
  ...options,
@@ -147,7 +149,7 @@ class Service {
147
149
  }
148
150
  buildSearchStreamRequestAndService(gaql, options) {
149
151
  const service = this.loadService("GoogleAdsServiceClient");
150
- const request = new protos_1.services.SearchGoogleAdsStreamRequest({
152
+ const request = new services.SearchGoogleAdsStreamRequest({
151
153
  customer_id: this.customerOptions.customer_id,
152
154
  query: gaql,
153
155
  ...options,
@@ -157,7 +159,7 @@ class Service {
157
159
  buildMutationRequestAndService(mutations, options) {
158
160
  const service = this.loadService("GoogleAdsServiceClient");
159
161
  const mutateOperations = mutations.map((mutation) => {
160
- const opKey = (0, utils_1.toSnakeCase)(`${mutation.entity}Operation`);
162
+ const opKey = toSnakeCase(`${mutation.entity}Operation`);
161
163
  const operation = {
162
164
  [mutation.operation ?? "create"]: mutation.resource,
163
165
  };
@@ -170,14 +172,14 @@ class Service {
170
172
  }
171
173
  else if (mutation.operation === "update") {
172
174
  // @ts-expect-error Resource operations should have updateMask defined
173
- operation.update_mask = (0, utils_1.getFieldMask)(mutation.resource);
175
+ operation.update_mask = getFieldMask(mutation.resource);
174
176
  }
175
- const mutateOperation = new protos_1.services.MutateOperation({
177
+ const mutateOperation = new services.MutateOperation({
176
178
  [opKey]: operation,
177
179
  });
178
180
  return mutateOperation;
179
181
  });
180
- const request = new protos_1.services.MutateGoogleAdsRequest({
182
+ const request = new services.MutateGoogleAdsRequest({
181
183
  customer_id: this.customerOptions.customer_id,
182
184
  mutate_operations: mutateOperations,
183
185
  ...options,
@@ -199,7 +201,7 @@ class Service {
199
201
  }
200
202
  else if (type === "update") {
201
203
  // @ts-expect-error Field required for updates
202
- op.update_mask = (0, utils_1.getFieldMask)(
204
+ op.update_mask = getFieldMask(
203
205
  // @ts-expect-error Message types have a toObject method
204
206
  message.toObject(e, {
205
207
  defaults: false,
@@ -218,4 +220,3 @@ class Service {
218
220
  return request;
219
221
  }
220
222
  }
221
- exports.Service = Service;