@pipedream/google_ads 0.7.0 → 1.0.0

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 (54) hide show
  1. package/README.md +4 -4
  2. package/actions/add-contact-to-list-by-email/add-contact-to-list-by-email.mjs +1 -1
  3. package/actions/common/bidding.mjs +196 -0
  4. package/actions/common/conversion-upload.mjs +131 -0
  5. package/actions/common/props.mjs +1 -1
  6. package/actions/create-ad-group-report/create-ad-group-report.mjs +2 -2
  7. package/actions/create-ad-report/create-ad-report.mjs +2 -2
  8. package/actions/create-campaign-report/create-campaign-report.mjs +2 -2
  9. package/actions/create-customer-list/common-constants.mjs +10 -10
  10. package/actions/create-customer-list/create-customer-list.mjs +3 -3
  11. package/actions/create-customer-report/create-customer-report.mjs +2 -2
  12. package/actions/create-or-remove-campaign-criteria/create-or-remove-campaign-criteria.mjs +214 -0
  13. package/actions/create-or-remove-campaign-shared-set/create-or-remove-campaign-shared-set.mjs +155 -0
  14. package/actions/create-or-remove-shared-criteria/create-or-remove-shared-criteria.mjs +180 -0
  15. package/actions/create-or-update-ad-group/create-or-update-ad-group.mjs +315 -0
  16. package/actions/create-or-update-ad-group-ad/create-or-update-ad-group-ad.mjs +203 -0
  17. package/actions/create-or-update-bidding-strategy/create-or-update-bidding-strategy.mjs +185 -0
  18. package/actions/create-or-update-campaign/create-or-update-campaign.mjs +300 -0
  19. package/actions/create-or-update-campaign-budget/create-or-update-campaign-budget.mjs +212 -0
  20. package/actions/create-or-update-keywords/create-or-update-keywords.mjs +275 -0
  21. package/actions/create-or-update-shared-sets/create-or-update-shared-sets.mjs +180 -0
  22. package/actions/create-report/create-report.mjs +5 -7
  23. package/actions/create-responsive-search-ad/create-responsive-search-ad.mjs +202 -0
  24. package/actions/generate-keyword-ideas/generate-keyword-ideas.mjs +3 -3
  25. package/actions/get-keyword-quality-scores/get-keyword-quality-scores.mjs +107 -0
  26. package/actions/list-account-id-options/list-account-id-options.mjs +1 -1
  27. package/actions/list-ad-group-ads/list-ad-group-ads.mjs +55 -0
  28. package/actions/list-ad-group-criteria/list-ad-group-criteria.mjs +55 -0
  29. package/actions/list-ad-groups/list-ad-groups.mjs +55 -0
  30. package/actions/list-bidding-strategies/list-bidding-strategies.mjs +55 -0
  31. package/actions/list-campaign-budgets/list-campaign-budgets.mjs +55 -0
  32. package/actions/list-campaign-criteria/list-campaign-criteria.mjs +55 -0
  33. package/actions/list-campaign-shared-sets/list-campaign-shared-sets.mjs +55 -0
  34. package/actions/list-campaigns/list-campaigns.mjs +55 -0
  35. package/actions/list-customer-clients/list-customer-clients.mjs +2 -2
  36. package/actions/list-keywords/list-keywords.mjs +55 -0
  37. package/actions/list-shared-criteria/list-shared-criteria.mjs +55 -0
  38. package/actions/list-shared-sets/list-shared-sets.mjs +55 -0
  39. package/actions/send-offline-conversion/send-offline-conversion.mjs +4 -4
  40. package/actions/update-campaign-ai-max-settings/update-campaign-ai-max-settings.mjs +167 -0
  41. package/actions/upload-call-conversion/upload-call-conversion.mjs +65 -0
  42. package/actions/upload-click-conversion/upload-click-conversion.mjs +121 -0
  43. package/common/common-report.mjs +5 -7
  44. package/common/constants.mjs +369 -0
  45. package/common/queries.mjs +4 -2
  46. package/common/resources/ad.mjs +25 -70
  47. package/common/resources/adGroup.mjs +2 -3
  48. package/common/resources/campaign.mjs +7 -10
  49. package/common/resources/customer.mjs +3 -4
  50. package/common/utils.mjs +4 -0
  51. package/google_ads.app.mjs +657 -19
  52. package/package.json +1 -1
  53. package/sources/new-campaign-created/new-campaign-created.mjs +3 -3
  54. package/sources/new-lead-form-entry/new-lead-form-entry.mjs +3 -3
@@ -0,0 +1,315 @@
1
+ import { ConfigurationError } from "@pipedream/platform";
2
+ import googleAds from "../../google_ads.app.mjs";
3
+ import {
4
+ AD_GROUP_STATUSES,
5
+ AD_GROUP_TYPES,
6
+ AD_ROTATION_MODES,
7
+ CAMPAIGN_OPERATION_TYPES,
8
+ } from "../../common/constants.mjs";
9
+ import { parseObject } from "../../common/utils.mjs";
10
+ import { getAdditionalFields } from "../common/props.mjs";
11
+
12
+ const docLink =
13
+ "https://developers.google.com/google-ads/api/reference/rpc/v25/AdGroupService/MutateAdGroups?transport=rest";
14
+
15
+ export default {
16
+ key: "google_ads-create-or-update-ad-group",
17
+ name: "Create or Update Ad Group",
18
+ description: `Creates or updates an ad group. [See the documentation](${docLink})`,
19
+ version: "0.1.0",
20
+ type: "action",
21
+ annotations: {
22
+ destructiveHint: true,
23
+ openWorldHint: true,
24
+ readOnlyHint: false,
25
+ },
26
+ props: {
27
+ googleAds,
28
+ accountId: {
29
+ propDefinition: [
30
+ googleAds,
31
+ "accountId",
32
+ ],
33
+ },
34
+ customerClientId: {
35
+ propDefinition: [
36
+ googleAds,
37
+ "customerClientId",
38
+ ({ accountId }) => ({
39
+ accountId,
40
+ }),
41
+ ],
42
+ optional: true,
43
+ },
44
+ operationType: {
45
+ type: "string",
46
+ label: "Operation Type",
47
+ description: "Whether to create, update, or remove an ad group.",
48
+ options: CAMPAIGN_OPERATION_TYPES,
49
+ },
50
+ adGroupId: {
51
+ propDefinition: [
52
+ googleAds,
53
+ "adGroupId",
54
+ ({
55
+ accountId, customerClientId,
56
+ }) => ({
57
+ accountId,
58
+ customerClientId,
59
+ }),
60
+ ],
61
+ description: "The ad group to update or remove. Required for **Update** and **Remove** operations.",
62
+ optional: true,
63
+ },
64
+ campaignId: {
65
+ propDefinition: [
66
+ googleAds,
67
+ "campaignId",
68
+ ({
69
+ accountId, customerClientId,
70
+ }) => ({
71
+ accountId,
72
+ customerClientId,
73
+ }),
74
+ ],
75
+ description: "The campaign this ad group belongs to. Required for **Create** operations.",
76
+ optional: true,
77
+ },
78
+ updateMask: {
79
+ type: "string",
80
+ label: "Update Mask",
81
+ description: "Comma-separated list of fields to update (e.g., `name,status`). Required for **Update** operations.",
82
+ optional: true,
83
+ },
84
+ name: {
85
+ type: "string",
86
+ label: "Name",
87
+ description: "The name of the ad group. Required for **Create** operations.",
88
+ optional: true,
89
+ },
90
+ type: {
91
+ type: "string",
92
+ label: "Type",
93
+ description: "The type of the ad group. Immutable after creation — only used for **Create** operations.",
94
+ options: AD_GROUP_TYPES,
95
+ optional: true,
96
+ },
97
+ status: {
98
+ type: "string",
99
+ label: "Status",
100
+ description: "The status of the ad group.",
101
+ options: AD_GROUP_STATUSES,
102
+ optional: true,
103
+ },
104
+ cpcBidMicros: {
105
+ type: "integer",
106
+ label: "CPC Bid (Micros)",
107
+ description: "The maximum CPC (cost-per-click) bid in micros (e.g., `1000000` = $1.00).",
108
+ optional: true,
109
+ },
110
+ cpmBidMicros: {
111
+ type: "integer",
112
+ label: "CPM Bid (Micros)",
113
+ description: "The maximum CPM (cost-per-thousand impressions) bid in micros.",
114
+ optional: true,
115
+ },
116
+ cpvBidMicros: {
117
+ type: "integer",
118
+ label: "CPV Bid (Micros)",
119
+ description: "The maximum CPV (cost-per-view) bid in micros.",
120
+ optional: true,
121
+ },
122
+ targetCpaMicros: {
123
+ type: "integer",
124
+ label: "Target CPA (Micros)",
125
+ description: "The target CPA (cost-per-acquisition) in micros.",
126
+ optional: true,
127
+ },
128
+ targetCpmMicros: {
129
+ type: "integer",
130
+ label: "Target CPM (Micros)",
131
+ description: "The target CPM (cost-per-thousand impressions) in micros.",
132
+ optional: true,
133
+ },
134
+ targetRoas: {
135
+ type: "string",
136
+ label: "Target ROAS",
137
+ description: "The target ROAS (return on ad spend) as a decimal (e.g., `3.5` for 350%).",
138
+ optional: true,
139
+ },
140
+ trackingUrlTemplate: {
141
+ type: "string",
142
+ label: "Tracking URL Template",
143
+ description: "The URL template for constructing a tracking URL.",
144
+ optional: true,
145
+ },
146
+ finalUrlSuffix: {
147
+ type: "string",
148
+ label: "Final URL Suffix",
149
+ description: "The suffix used to append query parameters to landing page URLs.",
150
+ optional: true,
151
+ },
152
+ adRotationMode: {
153
+ type: "string",
154
+ label: "Ad Rotation Mode",
155
+ description: "How ads within the ad group are served relative to one another.",
156
+ options: AD_ROTATION_MODES,
157
+ optional: true,
158
+ },
159
+ additionalFields: getAdditionalFields(docLink),
160
+ },
161
+ async run({ $ }) {
162
+ const {
163
+ googleAds,
164
+ accountId,
165
+ customerClientId,
166
+ operationType,
167
+ adGroupId,
168
+ campaignId,
169
+ updateMask,
170
+ name,
171
+ type,
172
+ status,
173
+ cpcBidMicros,
174
+ cpmBidMicros,
175
+ cpvBidMicros,
176
+ targetCpaMicros,
177
+ targetCpmMicros,
178
+ targetRoas,
179
+ trackingUrlTemplate,
180
+ finalUrlSuffix,
181
+ adRotationMode,
182
+ additionalFields,
183
+ } = this;
184
+
185
+ if ((operationType === "update" || operationType === "remove") && !adGroupId) {
186
+ throw new ConfigurationError(
187
+ "**Ad Group** is required for Update and Remove operations.",
188
+ );
189
+ }
190
+
191
+ if (operationType === "update" && !updateMask) {
192
+ throw new ConfigurationError(
193
+ "**Update Mask** is required for Update operations.",
194
+ );
195
+ }
196
+
197
+ if (operationType === "create") {
198
+ if (!name) {
199
+ throw new ConfigurationError(
200
+ "**Name** is required for Create operations.",
201
+ );
202
+ }
203
+ if (!campaignId) {
204
+ throw new ConfigurationError(
205
+ "**Campaign** is required for Create operations.",
206
+ );
207
+ }
208
+ }
209
+
210
+ const customerId = customerClientId ?? accountId;
211
+ const resourceName = adGroupId
212
+ ? `customers/${customerId}/adGroups/${adGroupId}`
213
+ : undefined;
214
+ const campaign = campaignId
215
+ ? `customers/${customerId}/campaigns/${campaignId}`
216
+ : undefined;
217
+
218
+ let parsedTargetRoas;
219
+ if (targetRoas !== undefined) {
220
+ parsedTargetRoas = parseFloat(targetRoas);
221
+ if (!Number.isFinite(parsedTargetRoas)) {
222
+ throw new ConfigurationError(
223
+ `**Target ROAS** must be a valid decimal number (e.g., \`3.5\`), got: \`${targetRoas}\`.`,
224
+ );
225
+ }
226
+ }
227
+
228
+ let operation;
229
+
230
+ if (operationType === "remove") {
231
+ operation = {
232
+ remove: resourceName,
233
+ };
234
+ } else {
235
+ const adGroupData = {
236
+ ...(resourceName && {
237
+ resourceName,
238
+ }),
239
+ ...(campaign && {
240
+ campaign,
241
+ }),
242
+ ...(name && {
243
+ name,
244
+ }),
245
+ ...(type && {
246
+ type,
247
+ }),
248
+ ...(status && {
249
+ status,
250
+ }),
251
+ ...(cpcBidMicros !== undefined && {
252
+ cpcBidMicros,
253
+ }),
254
+ ...(cpmBidMicros !== undefined && {
255
+ cpmBidMicros,
256
+ }),
257
+ ...(cpvBidMicros !== undefined && {
258
+ cpvBidMicros,
259
+ }),
260
+ ...(targetCpaMicros !== undefined && {
261
+ targetCpaMicros,
262
+ }),
263
+ ...(targetCpmMicros !== undefined && {
264
+ targetCpmMicros,
265
+ }),
266
+ ...(parsedTargetRoas !== undefined && {
267
+ targetRoas: parsedTargetRoas,
268
+ }),
269
+ ...(trackingUrlTemplate && {
270
+ trackingUrlTemplate,
271
+ }),
272
+ ...(finalUrlSuffix && {
273
+ finalUrlSuffix,
274
+ }),
275
+ ...(adRotationMode && {
276
+ adRotationMode,
277
+ }),
278
+ ...parseObject(additionalFields),
279
+ };
280
+
281
+ if (operationType === "update") {
282
+ operation = {
283
+ update: adGroupData,
284
+ updateMask,
285
+ };
286
+ } else {
287
+ operation = {
288
+ create: adGroupData,
289
+ };
290
+ }
291
+ }
292
+
293
+ const response = await googleAds.mutateAdGroup({
294
+ $,
295
+ accountId,
296
+ customerClientId,
297
+ data: {
298
+ operations: [
299
+ operation,
300
+ ],
301
+ },
302
+ });
303
+
304
+ const result = response?.results?.[0];
305
+ const id = result?.resourceName?.split("/").pop();
306
+
307
+ $.export(
308
+ "$summary",
309
+ `Successfully ${operationType}d ad group${id
310
+ ? ` with ID \`${id}\``
311
+ : ""}.`,
312
+ );
313
+ return response;
314
+ },
315
+ };
@@ -0,0 +1,203 @@
1
+ import { ConfigurationError } from "@pipedream/platform";
2
+ import googleAds from "../../google_ads.app.mjs";
3
+ import {
4
+ AD_GROUP_STATUSES, CAMPAIGN_OPERATION_TYPES,
5
+ } from "../../common/constants.mjs";
6
+ import {
7
+ parseObject, parseStringObject,
8
+ } from "../../common/utils.mjs";
9
+ import { getAdditionalFields } from "../common/props.mjs";
10
+
11
+ const docLink =
12
+ "https://developers.google.com/google-ads/api/reference/rpc/v25/AdGroupAdService/MutateAdGroupAds?transport=rest";
13
+
14
+ export default {
15
+ key: "google_ads-create-or-update-ad-group-ad",
16
+ name: "Create, Update, or Remove Ad Group Ad",
17
+ description: `Creates, updates, or removes an ad group ad. [See the documentation](${docLink})`,
18
+ version: "0.0.2",
19
+ type: "action",
20
+ annotations: {
21
+ destructiveHint: true,
22
+ openWorldHint: true,
23
+ readOnlyHint: false,
24
+ },
25
+ props: {
26
+ googleAds,
27
+ accountId: {
28
+ propDefinition: [
29
+ googleAds,
30
+ "accountId",
31
+ ],
32
+ },
33
+ customerClientId: {
34
+ propDefinition: [
35
+ googleAds,
36
+ "customerClientId",
37
+ ({ accountId }) => ({
38
+ accountId,
39
+ }),
40
+ ],
41
+ optional: true,
42
+ },
43
+ operationType: {
44
+ type: "string",
45
+ label: "Operation Type",
46
+ description: "Whether to create, update, or remove an ad group ad.",
47
+ options: CAMPAIGN_OPERATION_TYPES,
48
+ },
49
+ adGroupAdId: {
50
+ propDefinition: [
51
+ googleAds,
52
+ "adGroupAdId",
53
+ ({
54
+ accountId, customerClientId,
55
+ }) => ({
56
+ accountId,
57
+ customerClientId,
58
+ }),
59
+ ],
60
+ description: "The ad to update or remove. Required for **Update** and **Remove** operations.",
61
+ optional: true,
62
+ },
63
+ adGroupId: {
64
+ propDefinition: [
65
+ googleAds,
66
+ "adGroupId",
67
+ ({
68
+ accountId, customerClientId,
69
+ }) => ({
70
+ accountId,
71
+ customerClientId,
72
+ }),
73
+ ],
74
+ description: "The ad group this ad belongs to. Required for **Create** operations.",
75
+ optional: true,
76
+ },
77
+ updateMask: {
78
+ type: "string",
79
+ label: "Update Mask",
80
+ description: "Comma-separated list of fields to update (e.g., `status,ad.finalUrls`). Required for **Update** operations.",
81
+ optional: true,
82
+ },
83
+ status: {
84
+ type: "string",
85
+ label: "Status",
86
+ description: "The status of the ad group ad.",
87
+ options: AD_GROUP_STATUSES,
88
+ optional: true,
89
+ },
90
+ ad: {
91
+ type: "string",
92
+ label: "Ad",
93
+ description: "JSON object specifying the ad content. Required for **Create** operations. For creates, include the ad type-specific fields and `finalUrls` — e.g., `{\"responsiveSearchAd\": {\"headlines\": [{\"text\": \"Headline\"}], \"descriptions\": [{\"text\": \"Desc\"}]}, \"finalUrls\": [\"https://example.com\"]}`. For updates, only include mutable fields — e.g., `{\"finalUrls\": [\"https://example.com\"], \"trackingUrlTemplate\": \"https://tracker.com?url={lpurl}\"}`.",
94
+ optional: true,
95
+ },
96
+ additionalFields: getAdditionalFields(docLink),
97
+ },
98
+ async run({ $ }) {
99
+ const {
100
+ googleAds,
101
+ accountId,
102
+ customerClientId,
103
+ operationType,
104
+ adGroupAdId,
105
+ adGroupId,
106
+ updateMask,
107
+ status,
108
+ ad,
109
+ additionalFields,
110
+ } = this;
111
+
112
+ if ((operationType === "update" || operationType === "remove") && !adGroupAdId) {
113
+ throw new ConfigurationError(
114
+ "**Ad Group Ad** is required for Update and Remove operations.",
115
+ );
116
+ }
117
+
118
+ if (operationType === "update" && !updateMask) {
119
+ throw new ConfigurationError(
120
+ "**Update Mask** is required for Update operations.",
121
+ );
122
+ }
123
+
124
+ if (operationType === "create") {
125
+ if (!adGroupId) {
126
+ throw new ConfigurationError(
127
+ "**Ad Group** is required for Create operations.",
128
+ );
129
+ }
130
+ if (!ad) {
131
+ throw new ConfigurationError(
132
+ "**Ad** is required for Create operations.",
133
+ );
134
+ }
135
+ }
136
+
137
+ const customerId = customerClientId ?? accountId;
138
+ const adGroup = adGroupId
139
+ ? `customers/${customerId}/adGroups/${adGroupId}`
140
+ : undefined;
141
+
142
+ let operation;
143
+
144
+ if (operationType === "remove") {
145
+ operation = {
146
+ remove: adGroupAdId,
147
+ };
148
+ } else {
149
+ const parsedAd = ad
150
+ ? parseStringObject(ad)
151
+ : undefined;
152
+
153
+ const adGroupAdData = {
154
+ ...(adGroupAdId && {
155
+ resourceName: adGroupAdId,
156
+ }),
157
+ ...(adGroup && {
158
+ adGroup,
159
+ }),
160
+ ...(status && {
161
+ status,
162
+ }),
163
+ ...(parsedAd && {
164
+ ad: parsedAd,
165
+ }),
166
+ ...parseObject(additionalFields),
167
+ };
168
+
169
+ if (operationType === "update") {
170
+ operation = {
171
+ update: adGroupAdData,
172
+ updateMask,
173
+ };
174
+ } else {
175
+ operation = {
176
+ create: adGroupAdData,
177
+ };
178
+ }
179
+ }
180
+
181
+ const response = await googleAds.mutateAdGroupAd({
182
+ $,
183
+ accountId,
184
+ customerClientId,
185
+ data: {
186
+ operations: [
187
+ operation,
188
+ ],
189
+ },
190
+ });
191
+
192
+ const result = response?.results?.[0];
193
+ const id = result?.resourceName?.split("/").pop();
194
+
195
+ $.export(
196
+ "$summary",
197
+ `Successfully ${operationType}d ad group ad${id
198
+ ? ` with ID \`${id}\``
199
+ : ""}.`,
200
+ );
201
+ return response;
202
+ },
203
+ };
@@ -0,0 +1,185 @@
1
+ import { ConfigurationError } from "@pipedream/platform";
2
+ import googleAds from "../../google_ads.app.mjs";
3
+ import {
4
+ CAMPAIGN_OPERATION_TYPES,
5
+ PORTFOLIO_BIDDING_STRATEGY_TYPES,
6
+ } from "../../common/constants.mjs";
7
+ import { parseObject } from "../../common/utils.mjs";
8
+ import { getAdditionalFields } from "../common/props.mjs";
9
+ import {
10
+ buildBiddingScheme, getSchemeProps, PORTFOLIO_BIDDING_SCHEMES,
11
+ } from "../common/bidding.mjs";
12
+
13
+ const docLink =
14
+ "https://developers.google.com/google-ads/api/reference/rpc/v25/BiddingStrategyService/MutateBiddingStrategies?transport=rest";
15
+
16
+ export default {
17
+ key: "google_ads-create-or-update-bidding-strategy",
18
+ name: "Create or Update Bidding Strategy",
19
+ description: `Creates, updates, or removes a portfolio bidding strategy. [See the documentation](${docLink})`,
20
+ version: "1.0.0",
21
+ type: "action",
22
+ annotations: {
23
+ destructiveHint: true,
24
+ openWorldHint: true,
25
+ readOnlyHint: false,
26
+ },
27
+ props: {
28
+ googleAds,
29
+ accountId: {
30
+ propDefinition: [
31
+ googleAds,
32
+ "accountId",
33
+ ],
34
+ },
35
+ customerClientId: {
36
+ propDefinition: [
37
+ googleAds,
38
+ "customerClientId",
39
+ ({ accountId }) => ({
40
+ accountId,
41
+ }),
42
+ ],
43
+ optional: true,
44
+ },
45
+ operationType: {
46
+ type: "string",
47
+ label: "Operation Type",
48
+ description: "Whether to create, update, or remove a bidding strategy.",
49
+ options: CAMPAIGN_OPERATION_TYPES,
50
+ },
51
+ biddingStrategyId: {
52
+ propDefinition: [
53
+ googleAds,
54
+ "biddingStrategyId",
55
+ ({
56
+ accountId, customerClientId,
57
+ }) => ({
58
+ accountId,
59
+ customerClientId,
60
+ }),
61
+ ],
62
+ description: "The bidding strategy to update or remove. Required for **Update** and **Remove** operations.",
63
+ optional: true,
64
+ },
65
+ updateMask: {
66
+ type: "string",
67
+ label: "Update Mask",
68
+ description: "Comma-separated list of fields to update (e.g., `name`). Required for **Update** operations.",
69
+ optional: true,
70
+ },
71
+ name: {
72
+ type: "string",
73
+ label: "Name",
74
+ description: "The name of the bidding strategy. Required for **Create** operations.",
75
+ optional: true,
76
+ },
77
+ type: {
78
+ type: "string",
79
+ label: "Type",
80
+ description: "The type of the bidding strategy. Required for **Create** operations. Immutable after creation.",
81
+ options: PORTFOLIO_BIDDING_STRATEGY_TYPES,
82
+ optional: true,
83
+ },
84
+ ...getSchemeProps(PORTFOLIO_BIDDING_SCHEMES),
85
+ additionalFields: getAdditionalFields(docLink),
86
+ },
87
+ async run({ $ }) {
88
+ const {
89
+ googleAds,
90
+ accountId,
91
+ customerClientId,
92
+ operationType,
93
+ biddingStrategyId,
94
+ updateMask,
95
+ name,
96
+ type,
97
+ additionalFields,
98
+ } = this;
99
+
100
+ if ((operationType === "update" || operationType === "remove") && !biddingStrategyId) {
101
+ throw new ConfigurationError(
102
+ "**Bidding Strategy** is required for Update and Remove operations.",
103
+ );
104
+ }
105
+
106
+ if (operationType === "update" && !updateMask) {
107
+ throw new ConfigurationError(
108
+ "**Update Mask** is required for Update operations.",
109
+ );
110
+ }
111
+
112
+ if (operationType === "create") {
113
+ if (!name) {
114
+ throw new ConfigurationError(
115
+ "**Name** is required for Create operations.",
116
+ );
117
+ }
118
+ if (!type) {
119
+ throw new ConfigurationError(
120
+ "**Type** is required for Create operations.",
121
+ );
122
+ }
123
+ }
124
+
125
+ const customerId = customerClientId ?? accountId;
126
+ const resourceName = biddingStrategyId
127
+ ? `customers/${customerId}/biddingStrategies/${biddingStrategyId}`
128
+ : undefined;
129
+
130
+ let operation;
131
+
132
+ if (operationType === "remove") {
133
+ operation = {
134
+ remove: resourceName,
135
+ };
136
+ } else {
137
+ const strategyData = {
138
+ ...(resourceName && {
139
+ resourceName,
140
+ }),
141
+ ...(name && {
142
+ name,
143
+ }),
144
+ ...(type && {
145
+ type,
146
+ }),
147
+ ...buildBiddingScheme(PORTFOLIO_BIDDING_SCHEMES, type, this),
148
+ ...parseObject(additionalFields),
149
+ };
150
+
151
+ if (operationType === "update") {
152
+ operation = {
153
+ update: strategyData,
154
+ updateMask,
155
+ };
156
+ } else {
157
+ operation = {
158
+ create: strategyData,
159
+ };
160
+ }
161
+ }
162
+
163
+ const response = await googleAds.mutateBiddingStrategies({
164
+ $,
165
+ accountId,
166
+ customerClientId,
167
+ data: {
168
+ operations: [
169
+ operation,
170
+ ],
171
+ },
172
+ });
173
+
174
+ const result = response?.results?.[0];
175
+ const id = result?.resourceName?.split("/").pop();
176
+
177
+ $.export(
178
+ "$summary",
179
+ `Successfully ${operationType}d bidding strategy${id
180
+ ? ` with ID \`${id}\``
181
+ : ""}.`,
182
+ );
183
+ return response;
184
+ },
185
+ };