@crvouga/mockingbird-service-google-ads 1.2.0 → 1.3.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.
@@ -2188,7 +2188,7 @@ var stateAdminRoutes = (routes2) => {
2188
2188
  };
2189
2189
 
2190
2190
  // ../core/dist/version.js
2191
- var PACKAGE_VERSION = true ? "1.2.0" : UNRELEASED_VERSION;
2191
+ var PACKAGE_VERSION = true ? "1.3.0" : UNRELEASED_VERSION;
2192
2192
 
2193
2193
  // ../core/dist/webhooks.js
2194
2194
  var json4 = (status, body) => new Response(JSON.stringify(body), {
@@ -3080,8 +3080,14 @@ var Rejection = class extends Error {
3080
3080
  }
3081
3081
  status;
3082
3082
  detail;
3083
+ /** A Google Ads failure: google.rpc.Status wrapping a GoogleAdsFailure detail. */
3083
3084
  response(requestId) {
3084
- return rpcError(this.status, this.message, [adsFailure([this.detail], requestId)]);
3085
+ const message = this.status === 400 ? "Request contains an invalid argument." : this.message;
3086
+ return rpcError(this.status, message, [adsFailure([this.detail], requestId)]);
3087
+ }
3088
+ /** Any other Google API (Analytics Data): a plain google.rpc.Status with no Ads detail. */
3089
+ plain() {
3090
+ return rpcError(this.status, this.message);
3085
3091
  }
3086
3092
  };
3087
3093
  function reject(code, message, kind = "requestError", status = 400, field) {
@@ -3135,6 +3141,7 @@ var fingerprint = (v) => Array.from(
3135
3141
  sha256(new TextEncoder().encode(JSON.stringify(v))),
3136
3142
  (b) => b.toString(16).padStart(2, "0")
3137
3143
  ).join("");
3144
+ var publicSettings = ["reportingLagMs", "pageTokenTtlMs", "futureToleranceMs", "searchPageSize"];
3138
3145
  var DEFAULT_CUSTOMERS = [
3139
3146
  {
3140
3147
  id: DEFAULT_CUSTOMER,
@@ -3267,19 +3274,44 @@ var GoogleAdsState = class {
3267
3274
  return this.vault.open(value, JSON.stringify([this.publicNamespace, kind, id]));
3268
3275
  }
3269
3276
  configure(value) {
3270
- if (Object.keys(value).some(
3271
- (k) => !["reportingLagMs", "pageTokenTtlMs", "futureToleranceMs"].includes(k)
3272
- ))
3273
- invalid("Unknown setting");
3277
+ if (Object.keys(value).some((k) => !publicSettings.includes(k))) invalid("Unknown setting");
3274
3278
  const current = present(this.settings.get("settings"));
3275
- if (value.reportingLagMs !== void 0) integer(value.reportingLagMs, "reportingLagMs");
3276
- if (value.pageTokenTtlMs !== void 0) integer(value.pageTokenTtlMs, "pageTokenTtlMs", 1);
3279
+ const whole = (v, field, min = 0, max) => {
3280
+ if (typeof v !== "number") invalid(`Invalid ${field}`, field);
3281
+ integer(v, field, min, max);
3282
+ };
3283
+ if (value.reportingLagMs !== void 0) whole(value.reportingLagMs, "reportingLagMs");
3284
+ if (value.pageTokenTtlMs !== void 0) whole(value.pageTokenTtlMs, "pageTokenTtlMs", 1);
3277
3285
  if (value.futureToleranceMs !== void 0 && value.futureToleranceMs !== null)
3278
- integer(value.futureToleranceMs, "futureToleranceMs");
3286
+ whole(value.futureToleranceMs, "futureToleranceMs");
3287
+ if (value.searchPageSize !== void 0) whole(value.searchPageSize, "searchPageSize", 1, 1e4);
3279
3288
  const next = { ...current, ...value };
3280
3289
  this.settings.update("settings", next);
3281
3290
  return next;
3282
3291
  }
3292
+ view() {
3293
+ const { reportingLagMs, pageTokenTtlMs, futureToleranceMs, searchPageSize } = present(
3294
+ this.settings.get("settings")
3295
+ );
3296
+ return { reportingLagMs, pageTokenTtlMs, futureToleranceMs, searchPageSize };
3297
+ }
3298
+ /** Carry an ambiguous-write fault over to the next executed mutation. */
3299
+ deferAmbiguousWrite() {
3300
+ const current = present(this.settings.get("settings"));
3301
+ this.settings.update("settings", {
3302
+ ...current,
3303
+ pendingAmbiguousWrites: (current.pendingAmbiguousWrites ?? 0) + 1
3304
+ });
3305
+ }
3306
+ takeAmbiguousWrite() {
3307
+ const current = present(this.settings.get("settings"));
3308
+ if (!current.pendingAmbiguousWrites) return false;
3309
+ this.settings.update("settings", {
3310
+ ...current,
3311
+ pendingAmbiguousWrites: current.pendingAmbiguousWrites - 1
3312
+ });
3313
+ return true;
3314
+ }
3283
3315
  };
3284
3316
 
3285
3317
  // src/gaql.ts
@@ -3355,7 +3387,7 @@ function parseGAQL(input) {
3355
3387
  queryError("BAD_VALUE", "Expected a literal value");
3356
3388
  return t.value;
3357
3389
  };
3358
- require2("SELECT");
3390
+ if (!eat("SELECT")) queryError("EXPECTED_SELECT", "SELECT is missing at the beginning of query");
3359
3391
  const fields = [field()];
3360
3392
  while (eat(",")) fields.push(field());
3361
3393
  if (new Set(fields).size !== fields.length)
@@ -3715,6 +3747,7 @@ var AdsEngine = class {
3715
3747
  data = this.state.open(snapshot.sealed, "snapshot", snapshot.id);
3716
3748
  } else data = executeGAQL(this.state, customerId, query, this.now());
3717
3749
  if (validateOnly) return {};
3750
+ const pageSize = present(this.state.settings.get("settings")).searchPageSize ?? PAGE_SIZE;
3718
3751
  if (stream) {
3719
3752
  if (body.summaryRowSetting !== void 0 && !["NO_SUMMARY_ROW", "SUMMARY_ROW_WITH_RESULTS", "SUMMARY_ROW_ONLY", "UNSPECIFIED"].includes(
3720
3753
  String(body.summaryRowSetting)
@@ -3736,11 +3769,11 @@ var AdsEngine = class {
3736
3769
  }
3737
3770
  const result = {
3738
3771
  fieldMask: data.fieldMask,
3739
- ...omit ? {} : { results: data.results.slice(offset, offset + PAGE_SIZE) },
3772
+ ...omit ? {} : { results: data.results.slice(offset, offset + pageSize) },
3740
3773
  ...total ? { totalResultsCount: String(data.results.length) } : {},
3741
3774
  ...summary ? { summaryRow: data.summaryRow } : {}
3742
3775
  };
3743
- if (!omit && offset + PAGE_SIZE < data.results.length) {
3776
+ if (!omit && offset + pageSize < data.results.length) {
3744
3777
  if (!snapshotId) {
3745
3778
  snapshotId = this.state.ids.next("snapshot_");
3746
3779
  this.state.snapshots.insert(snapshotId, {
@@ -3752,11 +3785,10 @@ var AdsEngine = class {
3752
3785
  });
3753
3786
  }
3754
3787
  const previous = this.state.pageTokens.list({
3755
- where: (p) => p.snapshotId === snapshotId && p.offset === offset + PAGE_SIZE
3788
+ where: (p) => p.snapshotId === snapshotId && p.offset === offset + pageSize
3756
3789
  })[0]?.value;
3757
3790
  const id = previous?.id ?? this.state.ids.next("page_", 32);
3758
- if (!previous)
3759
- this.state.pageTokens.insert(id, { id, snapshotId, offset: offset + PAGE_SIZE });
3791
+ if (!previous) this.state.pageTokens.insert(id, { id, snapshotId, offset: offset + pageSize });
3760
3792
  result.nextPageToken = id;
3761
3793
  }
3762
3794
  return result;
@@ -3810,6 +3842,14 @@ var AdsEngine = class {
3810
3842
  reject("CAMPAIGN_BUDGET_IN_USE", "Campaign budget is in use", "campaignBudgetError");
3811
3843
  after = { ...before, status: "REMOVED" };
3812
3844
  } else {
3845
+ if (op.updateMask === void 0 || op.updateMask === "")
3846
+ reject(
3847
+ "FIELD_MASK_MISSING",
3848
+ "The field mask must be provided for update operations",
3849
+ "fieldMaskError",
3850
+ 400,
3851
+ "updateMask"
3852
+ );
3813
3853
  const mask = text(op.updateMask, "updateMask").split(",").map((s) => s.trim().replace(/_([a-z])/g, (_, c) => c.toUpperCase()));
3814
3854
  if (mask.some(
3815
3855
  (f) => ![
@@ -4422,7 +4462,7 @@ function compileFilter(input, permitted) {
4422
4462
  }
4423
4463
 
4424
4464
  // src/generated/openapi.ts
4425
- var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Google Ads v25 and GA4 local API subset","version":"0.1.0","x-mockingbird-upstream":{"note":"Bounded subset of official googleapis/googleapis proto SHA03a91044136a014466d4293eb1fe91f2b02075d2, Google Ads REST and GA4 Measurement Protocol/Data API documentation. Developer tokens are ignored under the September2026 policy."}},"servers":[{"url":"https://googleads.googleapis.com"}],"paths":{"/v25/customers/{customerId}/googleAds:search":{"post":{"operationId":"SearchGoogleAds","summary":"SearchGoogleAds","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}},"/v25/customers/{customerId}/googleAds:searchStream":{"post":{"operationId":"SearchStreamGoogleAds","summary":"SearchStreamGoogleAds","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchStreamRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StreamBatch"}}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}},"/v25/customers/{customerId}/campaignBudgets:mutate":{"post":{"operationId":"MutateCampaignBudgets","summary":"MutateCampaignBudgets","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetMutationRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetMutationResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}},"x-mockingbird":{"parity":{"safe":false}}}},"/v25/customers/{customerId}:uploadClickConversions":{"post":{"operationId":"UploadClickConversions","summary":"UploadClickConversions","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}},"x-mockingbird":{"parity":{"safe":false}}}},"/mp/collect":{"post":{"operationId":"CollectAnalyticsEvents","summary":"CollectAnalyticsEvents","parameters":[{"name":"measurement_id","in":"query","required":true,"schema":{"type":"string","example":"G-FIXTURE"}},{"name":"api_secret","in":"query","required":false,"schema":{"type":"string","example":"fixture-ga4-secret"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectRequest"}}}},"responses":{"204":{"description":"Success"}},"x-mockingbird":{"parity":{"safe":false}}}},"/debug/mp/collect":{"post":{"operationId":"ValidateAnalyticsEvents","summary":"ValidateAnalyticsEvents","parameters":[{"name":"measurement_id","in":"query","required":true,"schema":{"type":"string","example":"G-FIXTURE"}},{"name":"api_secret","in":"query","required":false,"schema":{"type":"string","example":"fixture-ga4-secret"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}},"/v1beta/properties/{propertyId}:runReport":{"post":{"operationId":"RunAnalyticsReport","summary":"RunAnalyticsReport","parameters":[{"name":"propertyId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}},"/v1beta/properties/{propertyId}:batchRunReports":{"post":{"operationId":"BatchRunAnalyticsReports","summary":"BatchRunAnalyticsReports","parameters":[{"name":"propertyId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchReportRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchReportResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}}},"components":{"schemas":{"AdsError":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"},"status":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"@type":{"type":"string"},"errors":{"type":"array","items":{"type":"object","properties":{"errorCode":{"type":"object","properties":{},"additionalProperties":{"type":"string"}},"message":{"type":"string"},"location":{"type":"object","properties":{"fieldPathElements":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"index":{"type":"integer","minimum":0}},"additionalProperties":false,"required":["fieldName"]}}},"additionalProperties":false}},"additionalProperties":false,"required":["errorCode","message"]}},"requestId":{"type":"string","x-mockingbird-volatile":{"kind":"id"}}},"additionalProperties":true}}},"additionalProperties":false,"required":["code","message","status"]}},"additionalProperties":false,"required":["error"]},"PartialFailure":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"additionalProperties":false,"required":["code","message","details"]},"Budget":{"type":"object","properties":{"resourceName":{"type":"string"},"id":{"type":"string","pattern":"^-?[0-9]+$"},"name":{"type":"string"},"amountMicros":{"type":"string","pattern":"^-?[0-9]+$"},"totalAmountMicros":{"type":"string","pattern":"^-?[0-9]+$"},"period":{"type":"string","enum":["DAILY","CUSTOM_PERIOD","UNSPECIFIED"]},"deliveryMethod":{"type":"string","enum":["STANDARD","UNSPECIFIED"]},"explicitlyShared":{"type":"boolean"},"status":{"type":"string"},"referenceCount":{"type":"string","pattern":"^-?[0-9]+$"}},"additionalProperties":true},"AdsRow":{"type":"object","properties":{"campaign":{"type":"object","properties":{"id":{"type":"string","pattern":"^-?[0-9]+$"},"resourceName":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"campaignBudget":{"type":"string"}},"additionalProperties":true},"campaignBudget":{"$ref":"#/components/schemas/Budget"},"conversionAction":{"type":"object","properties":{"id":{"type":"string","pattern":"^-?[0-9]+$"},"resourceName":{"type":"string"},"name":{"type":"string"},"category":{"type":"string"},"type":{"type":"string"},"status":{"type":"string"}},"additionalProperties":true},"customer":{"type":"object","properties":{"id":{"type":"string","pattern":"^-?[0-9]+$"},"resourceName":{"type":"string"},"descriptiveName":{"type":"string"},"currencyCode":{"type":"string"},"timeZone":{"type":"string"}},"additionalProperties":true},"metrics":{"type":"object","properties":{"costMicros":{"type":"string","pattern":"^-?[0-9]+$"},"clicks":{"type":"string","pattern":"^-?[0-9]+$"},"impressions":{"type":"string","pattern":"^-?[0-9]+$"},"conversions":{"type":"number"},"conversionsValue":{"type":"number"}},"additionalProperties":true},"segments":{"type":"object","properties":{"date":{"type":"string"},"conversionAction":{"type":"string"},"conversionActionCategory":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"SearchRequest":{"type":"object","properties":{"query":{"type":"string","minLength":1,"example":"SELECT campaign.id, campaign.name, metrics.cost_micros, metrics.clicks, metrics.impressions, metrics.conversions, metrics.conversions_value, segments.date FROM campaign ORDER BY campaign.id"},"pageToken":{"type":"string"},"pageSize":{"type":"integer","minimum":0},"validateOnly":{"type":"boolean"},"searchSettings":{"type":"object","properties":{"omitResults":{"type":"boolean"},"returnSummaryRow":{"type":"boolean"},"returnTotalResultsCount":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false,"required":["query"]},"SearchResponse":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/AdsRow"}},"nextPageToken":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"fieldMask":{"type":"string"},"totalResultsCount":{"type":"string","pattern":"^-?[0-9]+$"},"summaryRow":{"$ref":"#/components/schemas/AdsRow"}},"additionalProperties":false},"SearchStreamRequest":{"type":"object","properties":{"query":{"type":"string","minLength":1},"summaryRowSetting":{"type":"string","enum":["NO_SUMMARY_ROW","SUMMARY_ROW_WITH_RESULTS","SUMMARY_ROW_ONLY","UNSPECIFIED"]}},"additionalProperties":false,"required":["query"]},"StreamBatch":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/AdsRow"}},"fieldMask":{"type":"string"},"requestId":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"summaryRow":{"$ref":"#/components/schemas/AdsRow"}},"additionalProperties":false},"BudgetOperation":{"type":"object","properties":{"create":{"$ref":"#/components/schemas/Budget"},"update":{"$ref":"#/components/schemas/Budget"},"remove":{"type":"string"},"updateMask":{"type":"string"}},"additionalProperties":false},"BudgetMutationRequest":{"type":"object","properties":{"operations":{"type":"array","items":{"$ref":"#/components/schemas/BudgetOperation"},"minItems":1},"partialFailure":{"type":"boolean"},"validateOnly":{"type":"boolean"},"responseContentType":{"type":"string","enum":["RESOURCE_NAME_ONLY","MUTABLE_RESOURCE","UNSPECIFIED"]}},"additionalProperties":false,"required":["operations"]},"BudgetMutationResponse":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"resourceName":{"type":"string","x-mockingbird-resource":{"type":"google_campaign_budget","identity":true}},"campaignBudget":{"$ref":"#/components/schemas/Budget"}},"additionalProperties":false}},"partialFailureError":{"$ref":"#/components/schemas/PartialFailure"}},"additionalProperties":false},"Conversion":{"type":"object","properties":{"gclid":{"type":"string"},"gbraid":{"type":"string"},"wbraid":{"type":"string"},"conversionAction":{"type":"string"},"conversionDateTime":{"type":"string"},"conversionValue":{"type":"number"},"currencyCode":{"type":"string"},"orderId":{"type":"string"},"consent":{"type":"object","properties":{},"additionalProperties":true},"customVariables":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"userIdentifiers":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"additionalProperties":true,"required":["conversionAction","conversionDateTime"]},"ConversionRequest":{"type":"object","properties":{"conversions":{"type":"array","items":{"$ref":"#/components/schemas/Conversion"},"minItems":1},"partialFailure":{"type":"boolean"},"validateOnly":{"type":"boolean"},"jobId":{"type":"integer","minimum":0,"maximum":2147483647}},"additionalProperties":false,"required":["conversions","partialFailure"]},"ConversionResponse":{"type":"object","properties":{"jobId":{"type":"string","pattern":"^-?[0-9]+$","x-mockingbird-volatile":{"kind":"id"}},"partialFailureError":{"$ref":"#/components/schemas/PartialFailure"},"results":{"type":"array","items":{"type":"object","properties":{"gclid":{"type":"string"},"gbraid":{"type":"string"},"wbraid":{"type":"string"},"conversionAction":{"type":"string"},"conversionDateTime":{"type":"string"},"userIdentifiers":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"additionalProperties":false}}},"additionalProperties":false,"required":["jobId"]},"Event":{"type":"object","properties":{"name":{"type":"string"},"params":{"type":"object","properties":{},"additionalProperties":true},"timestamp_micros":{"type":"integer"}},"additionalProperties":true,"required":["name"]},"CollectRequest":{"type":"object","properties":{"client_id":{"type":"string"},"user_id":{"type":"string"},"timestamp_micros":{"type":"integer"},"events":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"validation_behavior":{"type":"string","enum":["RELAXED","ENFORCE_RECOMMENDATIONS"]},"user_properties":{"type":"object","properties":{},"additionalProperties":true},"consent":{"type":"object","properties":{},"additionalProperties":true},"non_personalized_ads":{"type":"boolean"}},"additionalProperties":true},"ValidationResponse":{"type":"object","properties":{"validationMessages":{"type":"array","items":{"type":"object","properties":{"fieldPath":{"type":"string"},"description":{"type":"string"},"validationCode":{"type":"string","enum":["VALUE_INVALID","VALUE_REQUIRED","NAME_INVALID","NAME_RESERVED","VALUE_OUT_OF_BOUNDS","EXCEEDED_MAX_ENTITIES","NAME_DUPLICATED"]}},"additionalProperties":false,"required":["fieldPath","description","validationCode"]}}},"additionalProperties":false,"required":["validationMessages"]},"ReportRequest":{"type":"object","properties":{"property":{"type":"string"},"dimensions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":false,"required":["name"]}},"metrics":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":false,"required":["name"]},"minItems":1},"dateRanges":{"type":"array","items":{"type":"object","properties":{"startDate":{"type":"string"},"endDate":{"type":"string"},"name":{"type":"string"}},"additionalProperties":false,"required":["startDate","endDate"]}},"dimensionFilter":{"type":"object","properties":{},"additionalProperties":true},"metricFilter":{"type":"object","properties":{},"additionalProperties":true},"offset":{"type":"string","pattern":"^-?[0-9]+$"},"limit":{"type":"string","pattern":"^-?[0-9]+$"},"orderBys":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"currencyCode":{"type":"string"},"keepEmptyRows":{"type":"boolean"},"returnPropertyQuota":{"type":"boolean"},"metricAggregations":{"type":"array","items":{"type":"string"}},"comparisons":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"cohortSpec":{"type":"object","properties":{},"additionalProperties":true}},"additionalProperties":false,"required":["metrics"]},"ReportResponse":{"type":"object","properties":{"dimensionHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":false,"required":["name"]}},"metricHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"}},"additionalProperties":false,"required":["name","type"]}},"rows":{"type":"array","items":{"type":"object","properties":{"dimensionValues":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"}},"additionalProperties":false,"required":["value"]}},"metricValues":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"}},"additionalProperties":false,"required":["value"]}}},"additionalProperties":false,"required":["dimensionValues","metricValues"]}},"rowCount":{"type":"integer","minimum":0},"metadata":{"type":"object","properties":{"currencyCode":{"type":"string"},"timeZone":{"type":"string"}},"additionalProperties":false,"required":["currencyCode","timeZone"]},"kind":{"type":"string"}},"additionalProperties":false,"required":["dimensionHeaders","metricHeaders","rows","rowCount","metadata","kind"]},"BatchReportRequest":{"type":"object","properties":{"requests":{"type":"array","items":{"$ref":"#/components/schemas/ReportRequest"},"minItems":1,"maxItems":5}},"additionalProperties":false,"required":["requests"]},"BatchReportResponse":{"type":"object","properties":{"reports":{"type":"array","items":{"$ref":"#/components/schemas/ReportResponse"}},"kind":{"type":"string"}},"additionalProperties":false,"required":["reports","kind"]}}}}`);
4465
+ var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Google Ads v25 and GA4 local API subset","version":"0.1.0","x-mockingbird-upstream":{"note":"Bounded subset of official googleapis/googleapis proto SHA03a91044136a014466d4293eb1fe91f2b02075d2, Google Ads REST and GA4 Measurement Protocol/Data API documentation. Developer tokens are ignored under the September2026 policy."}},"servers":[{"url":"https://googleads.googleapis.com"}],"paths":{"/v25/customers/{customerId}/googleAds:search":{"post":{"operationId":"SearchGoogleAds","summary":"SearchGoogleAds","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}},"/v25/customers/{customerId}/googleAds:searchStream":{"post":{"operationId":"SearchStreamGoogleAds","summary":"SearchStreamGoogleAds","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchStreamRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StreamBatch"}}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}},"/v25/customers/{customerId}/campaignBudgets:mutate":{"post":{"operationId":"MutateCampaignBudgets","summary":"MutateCampaignBudgets","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetMutationRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetMutationResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}},"x-mockingbird":{"parity":{"safe":false}}}},"/v25/customers/{customerId}:uploadClickConversions":{"post":{"operationId":"UploadClickConversions","summary":"UploadClickConversions","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}},"x-mockingbird":{"parity":{"safe":false}}}},"/mp/collect":{"post":{"operationId":"CollectAnalyticsEvents","summary":"CollectAnalyticsEvents","parameters":[{"name":"measurement_id","in":"query","required":true,"schema":{"type":"string","example":"G-FIXTURE"}},{"name":"api_secret","in":"query","required":false,"schema":{"type":"string","example":"fixture-ga4-secret"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectRequest"}}}},"responses":{"204":{"description":"Success"}},"x-mockingbird":{"parity":{"safe":false}}}},"/debug/mp/collect":{"post":{"operationId":"ValidateAnalyticsEvents","summary":"ValidateAnalyticsEvents","parameters":[{"name":"measurement_id","in":"query","required":true,"schema":{"type":"string","example":"G-FIXTURE"}},{"name":"api_secret","in":"query","required":false,"schema":{"type":"string","example":"fixture-ga4-secret"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}},"/v1beta/properties/{propertyId}:runReport":{"post":{"operationId":"RunAnalyticsReport","summary":"RunAnalyticsReport","parameters":[{"name":"propertyId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}},"/v1beta/properties/{propertyId}:batchRunReports":{"post":{"operationId":"BatchRunAnalyticsReports","summary":"BatchRunAnalyticsReports","parameters":[{"name":"propertyId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9]+$","example":"1000000001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchReportRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchReportResponse"}}}},"400":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"401":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"403":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"404":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"429":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"500":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}},"503":{"description":"Google RPC error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdsError"}}}}}}}},"components":{"schemas":{"AdsError":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"},"status":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"@type":{"type":"string"},"errors":{"type":"array","items":{"type":"object","properties":{"errorCode":{"type":"object","properties":{},"additionalProperties":{"type":"string"}},"message":{"type":"string"},"location":{"type":"object","properties":{"fieldPathElements":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"index":{"type":"integer","minimum":0}},"additionalProperties":false,"required":["fieldName"]}}},"additionalProperties":false},"details":{"type":"object","properties":{"quotaErrorDetails":{"type":"object","properties":{"rateScope":{"type":"string","enum":["ACCOUNT","DEVELOPER","UNSPECIFIED","UNKNOWN"]},"rateName":{"type":"string"},"retryDelay":{"type":"string","pattern":"^[0-9]+(\\\\.[0-9]+)?s$"}},"additionalProperties":false}},"additionalProperties":true}},"additionalProperties":false,"required":["errorCode","message"]}},"requestId":{"type":"string","x-mockingbird-volatile":{"kind":"id"}}},"additionalProperties":true}}},"additionalProperties":false,"required":["code","message","status"]}},"additionalProperties":false,"required":["error"]},"PartialFailure":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"additionalProperties":false,"required":["code","message","details"]},"Budget":{"type":"object","properties":{"resourceName":{"type":"string"},"id":{"type":"string","pattern":"^-?[0-9]+$"},"name":{"type":"string"},"amountMicros":{"type":"string","pattern":"^-?[0-9]+$"},"totalAmountMicros":{"type":"string","pattern":"^-?[0-9]+$"},"period":{"type":"string","enum":["DAILY","CUSTOM_PERIOD","UNSPECIFIED"]},"deliveryMethod":{"type":"string","enum":["STANDARD","UNSPECIFIED"]},"explicitlyShared":{"type":"boolean"},"status":{"type":"string"},"referenceCount":{"type":"string","pattern":"^-?[0-9]+$"}},"additionalProperties":true},"AdsRow":{"type":"object","properties":{"campaign":{"type":"object","properties":{"id":{"type":"string","pattern":"^-?[0-9]+$"},"resourceName":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"campaignBudget":{"type":"string"}},"additionalProperties":true},"campaignBudget":{"$ref":"#/components/schemas/Budget"},"conversionAction":{"type":"object","properties":{"id":{"type":"string","pattern":"^-?[0-9]+$"},"resourceName":{"type":"string"},"name":{"type":"string"},"category":{"type":"string"},"type":{"type":"string"},"status":{"type":"string"}},"additionalProperties":true},"customer":{"type":"object","properties":{"id":{"type":"string","pattern":"^-?[0-9]+$"},"resourceName":{"type":"string"},"descriptiveName":{"type":"string"},"currencyCode":{"type":"string"},"timeZone":{"type":"string"}},"additionalProperties":true},"metrics":{"type":"object","properties":{"costMicros":{"type":"string","pattern":"^-?[0-9]+$"},"clicks":{"type":"string","pattern":"^-?[0-9]+$"},"impressions":{"type":"string","pattern":"^-?[0-9]+$"},"conversions":{"type":"number"},"conversionsValue":{"type":"number"}},"additionalProperties":true},"segments":{"type":"object","properties":{"date":{"type":"string"},"conversionAction":{"type":"string"},"conversionActionCategory":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"SearchRequest":{"type":"object","properties":{"query":{"type":"string","minLength":1,"example":"SELECT campaign.id, campaign.name, metrics.cost_micros, metrics.clicks, metrics.impressions, metrics.conversions, metrics.conversions_value, segments.date FROM campaign ORDER BY campaign.id"},"pageToken":{"type":"string"},"pageSize":{"type":"integer","minimum":0},"validateOnly":{"type":"boolean"},"searchSettings":{"type":"object","properties":{"omitResults":{"type":"boolean"},"returnSummaryRow":{"type":"boolean"},"returnTotalResultsCount":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false,"required":["query"]},"SearchResponse":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/AdsRow"}},"nextPageToken":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"fieldMask":{"type":"string"},"totalResultsCount":{"type":"string","pattern":"^-?[0-9]+$"},"summaryRow":{"$ref":"#/components/schemas/AdsRow"}},"additionalProperties":false},"SearchStreamRequest":{"type":"object","properties":{"query":{"type":"string","minLength":1},"summaryRowSetting":{"type":"string","enum":["NO_SUMMARY_ROW","SUMMARY_ROW_WITH_RESULTS","SUMMARY_ROW_ONLY","UNSPECIFIED"]}},"additionalProperties":false,"required":["query"]},"StreamBatch":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/AdsRow"}},"fieldMask":{"type":"string"},"requestId":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"summaryRow":{"$ref":"#/components/schemas/AdsRow"}},"additionalProperties":false},"BudgetOperation":{"type":"object","properties":{"create":{"$ref":"#/components/schemas/Budget"},"update":{"$ref":"#/components/schemas/Budget"},"remove":{"type":"string"},"updateMask":{"type":"string"}},"additionalProperties":false},"BudgetMutationRequest":{"type":"object","properties":{"operations":{"type":"array","items":{"$ref":"#/components/schemas/BudgetOperation"},"minItems":1},"partialFailure":{"type":"boolean"},"validateOnly":{"type":"boolean"},"responseContentType":{"type":"string","enum":["RESOURCE_NAME_ONLY","MUTABLE_RESOURCE","UNSPECIFIED"]}},"additionalProperties":false,"required":["operations"]},"BudgetMutationResponse":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"resourceName":{"type":"string","x-mockingbird-resource":{"type":"google_campaign_budget","identity":true}},"campaignBudget":{"$ref":"#/components/schemas/Budget"}},"additionalProperties":false}},"partialFailureError":{"$ref":"#/components/schemas/PartialFailure"}},"additionalProperties":false},"Conversion":{"type":"object","properties":{"gclid":{"type":"string"},"gbraid":{"type":"string"},"wbraid":{"type":"string"},"conversionAction":{"type":"string"},"conversionDateTime":{"type":"string"},"conversionValue":{"type":"number"},"currencyCode":{"type":"string"},"orderId":{"type":"string"},"consent":{"type":"object","properties":{},"additionalProperties":true},"customVariables":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"userIdentifiers":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"additionalProperties":true,"required":["conversionAction","conversionDateTime"]},"ConversionRequest":{"type":"object","properties":{"conversions":{"type":"array","items":{"$ref":"#/components/schemas/Conversion"},"minItems":1},"partialFailure":{"type":"boolean"},"validateOnly":{"type":"boolean"},"jobId":{"type":"integer","minimum":0,"maximum":2147483647}},"additionalProperties":false,"required":["conversions","partialFailure"]},"ConversionResponse":{"type":"object","properties":{"jobId":{"type":"string","pattern":"^-?[0-9]+$","x-mockingbird-volatile":{"kind":"id"}},"partialFailureError":{"$ref":"#/components/schemas/PartialFailure"},"results":{"type":"array","items":{"type":"object","properties":{"gclid":{"type":"string"},"gbraid":{"type":"string"},"wbraid":{"type":"string"},"conversionAction":{"type":"string"},"conversionDateTime":{"type":"string"},"userIdentifiers":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"additionalProperties":false}}},"additionalProperties":false,"required":["jobId"]},"Event":{"type":"object","properties":{"name":{"type":"string"},"params":{"type":"object","properties":{},"additionalProperties":true},"timestamp_micros":{"type":"integer"}},"additionalProperties":true,"required":["name"]},"CollectRequest":{"type":"object","properties":{"client_id":{"type":"string"},"user_id":{"type":"string"},"timestamp_micros":{"type":"integer"},"events":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"validation_behavior":{"type":"string","enum":["RELAXED","ENFORCE_RECOMMENDATIONS"]},"user_properties":{"type":"object","properties":{},"additionalProperties":true},"consent":{"type":"object","properties":{},"additionalProperties":true},"non_personalized_ads":{"type":"boolean"}},"additionalProperties":true},"ValidationResponse":{"type":"object","properties":{"validationMessages":{"type":"array","items":{"type":"object","properties":{"fieldPath":{"type":"string"},"description":{"type":"string"},"validationCode":{"type":"string","enum":["VALUE_INVALID","VALUE_REQUIRED","NAME_INVALID","NAME_RESERVED","VALUE_OUT_OF_BOUNDS","EXCEEDED_MAX_ENTITIES","NAME_DUPLICATED"]}},"additionalProperties":false,"required":["fieldPath","description","validationCode"]}}},"additionalProperties":false,"required":["validationMessages"]},"ReportRequest":{"type":"object","properties":{"property":{"type":"string"},"dimensions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":false,"required":["name"]}},"metrics":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":false,"required":["name"]},"minItems":1},"dateRanges":{"type":"array","items":{"type":"object","properties":{"startDate":{"type":"string"},"endDate":{"type":"string"},"name":{"type":"string"}},"additionalProperties":false,"required":["startDate","endDate"]}},"dimensionFilter":{"type":"object","properties":{},"additionalProperties":true},"metricFilter":{"type":"object","properties":{},"additionalProperties":true},"offset":{"type":"string","pattern":"^-?[0-9]+$"},"limit":{"type":"string","pattern":"^-?[0-9]+$"},"orderBys":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"currencyCode":{"type":"string"},"keepEmptyRows":{"type":"boolean"},"returnPropertyQuota":{"type":"boolean"},"metricAggregations":{"type":"array","items":{"type":"string"}},"comparisons":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"cohortSpec":{"type":"object","properties":{},"additionalProperties":true}},"additionalProperties":false,"required":["metrics"]},"ReportResponse":{"type":"object","properties":{"dimensionHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":false,"required":["name"]}},"metricHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"}},"additionalProperties":false,"required":["name","type"]}},"rows":{"type":"array","items":{"type":"object","properties":{"dimensionValues":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"}},"additionalProperties":false,"required":["value"]}},"metricValues":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"}},"additionalProperties":false,"required":["value"]}}},"additionalProperties":false,"required":["dimensionValues","metricValues"]}},"rowCount":{"type":"integer","minimum":0},"metadata":{"type":"object","properties":{"currencyCode":{"type":"string"},"timeZone":{"type":"string"}},"additionalProperties":false,"required":["currencyCode","timeZone"]},"kind":{"type":"string"}},"additionalProperties":false,"required":["dimensionHeaders","metricHeaders","rows","rowCount","metadata","kind"]},"BatchReportRequest":{"type":"object","properties":{"requests":{"type":"array","items":{"$ref":"#/components/schemas/ReportRequest"},"minItems":1,"maxItems":5}},"additionalProperties":false,"required":["requests"]},"BatchReportResponse":{"type":"object","properties":{"reports":{"type":"array","items":{"$ref":"#/components/schemas/ReportResponse"}},"kind":{"type":"string"}},"additionalProperties":false,"required":["reports","kind"]}}}}`);
4426
4466
  var supportedOperationIds = ["SearchGoogleAds", "SearchStreamGoogleAds", "MutateCampaignBudgets", "UploadClickConversions", "CollectAnalyticsEvents", "ValidateAnalyticsEvents", "RunAnalyticsReport", "BatchRunAnalyticsReports"];
4427
4467
 
4428
4468
  // src/vault.ts
@@ -4457,24 +4497,36 @@ var Vault = class {
4457
4497
  };
4458
4498
 
4459
4499
  // src/runtime.ts
4460
- var faultBody = (status, name, kind, code) => ({
4500
+ var faultBody = (status, name, kind, code, message, details) => ({
4461
4501
  error: {
4462
4502
  code: status,
4463
- message: name,
4503
+ message,
4464
4504
  status: code,
4465
- details: [adsFailure([{ errorCode: { [kind]: name }, message: name }], "fixture-request")]
4505
+ details: [
4506
+ adsFailure(
4507
+ [{ errorCode: { [kind]: name }, message, ...details ? { details } : {} }],
4508
+ "fixture-request"
4509
+ )
4510
+ ]
4466
4511
  }
4467
4512
  });
4513
+ var quotaFault = (name, message) => ({
4514
+ count: 1,
4515
+ status: 429,
4516
+ headers: { "request-id": "fixture-request" },
4517
+ body: faultBody(429, name, "quotaError", "RESOURCE_EXHAUSTED", message, {
4518
+ quotaErrorDetails: { rateScope: "ACCOUNT", rateName: "Requests per account", retryDelay: "1s" }
4519
+ })
4520
+ });
4468
4521
  var GOOGLE_ADS_PRESETS = {
4469
4522
  quota_exhausted: {
4470
4523
  description: "Reject one request before mutation with Google RPC quota exhaustion",
4524
+ rules: [quotaFault("RESOURCE_EXHAUSTED", "Too many requests.")]
4525
+ },
4526
+ rate_limited: {
4527
+ description: "Reject one request before mutation with Google's short-term rate limit",
4471
4528
  rules: [
4472
- {
4473
- count: 1,
4474
- status: 429,
4475
- headers: { "retry-after": "1", "request-id": "fixture-request" },
4476
- body: faultBody(429, "RESOURCE_EXHAUSTED", "quotaError", "RESOURCE_EXHAUSTED")
4477
- }
4529
+ quotaFault("RESOURCE_TEMPORARILY_EXHAUSTED", "Too many requests in a short amount of time.")
4478
4530
  ]
4479
4531
  },
4480
4532
  server_error: {
@@ -4483,7 +4535,8 @@ var GOOGLE_ADS_PRESETS = {
4483
4535
  {
4484
4536
  count: 1,
4485
4537
  status: 500,
4486
- body: faultBody(500, "INTERNAL_ERROR", "internalError", "INTERNAL")
4538
+ headers: { "request-id": "fixture-request" },
4539
+ body: faultBody(500, "INTERNAL_ERROR", "internalError", "INTERNAL", "INTERNAL_ERROR")
4487
4540
  }
4488
4541
  ]
4489
4542
  },
@@ -4496,7 +4549,7 @@ var GOOGLE_ADS_PRESETS = {
4496
4549
  rules: [{ count: 1, delayMs: 50 }]
4497
4550
  },
4498
4551
  ambiguous_budget_write: {
4499
- description: "Commit one budget mutation then return 503; inspect before replaying",
4552
+ description: "Commit the next executed budget mutation then return 503; inspect before replaying",
4500
4553
  rules: [{ count: 1, operationId: "MutateCampaignBudgets", effect: "ambiguous_mutation" }]
4501
4554
  },
4502
4555
  partial_budget_failure: {
@@ -4532,15 +4585,11 @@ var routes = (runtime) => {
4532
4585
  () => Response.json({ inserted: runtime.instance(namespace).seedMetrics(body) }, { status: 201 })
4533
4586
  ),
4534
4587
  "POST /page-tokens/expire": ({ namespace }) => Response.json({ expired: runtime.instance(namespace).expirePageTokens() }),
4535
- "GET /settings": ({ namespace }) => {
4536
- const { reportingLagMs, pageTokenTtlMs, futureToleranceMs } = present(
4537
- runtime.instance(namespace).state.settings.get("settings")
4538
- );
4539
- return Response.json({ reportingLagMs, pageTokenTtlMs, futureToleranceMs });
4540
- },
4588
+ "GET /settings": ({ namespace }) => Response.json(runtime.instance(namespace).state.view()),
4541
4589
  "PUT /settings": ({ namespace, body }) => guarded(() => {
4542
- const { reportingLagMs, pageTokenTtlMs, futureToleranceMs } = runtime.instance(namespace).configure(record(body));
4543
- return Response.json({ reportingLagMs, pageTokenTtlMs, futureToleranceMs });
4590
+ const api = runtime.instance(namespace);
4591
+ api.configure(record(body));
4592
+ return Response.json(api.state.view());
4544
4593
  })
4545
4594
  };
4546
4595
  };
@@ -4575,6 +4624,7 @@ var createRuntime2 = (options = {}) => {
4575
4624
  var GOOGLE_ADS_NAMESPACE = "google-ads";
4576
4625
  var DEFAULT_ADMIN_KEY = "fixture-google-ads-admin";
4577
4626
  var isMP = (path) => path === "/mp/collect" || path === "/debug/mp/collect";
4627
+ var isAds = (path) => path.startsWith("/v25/");
4578
4628
  var GoogleAdsAPI = class {
4579
4629
  sqlite;
4580
4630
  state;
@@ -4628,7 +4678,9 @@ var GoogleAdsAPI = class {
4628
4678
  nextBudgetId: "9000000001",
4629
4679
  nextJobId: "2147483648",
4630
4680
  reportingLagMs: integer(options.reportingLagMs ?? 0, "reportingLagMs"),
4631
- pageTokenTtlMs: integer(options.pageTokenTtlMs ?? 36e5, "pageTokenTtlMs", 1),
4681
+ pageTokenTtlMs: integer(options.pageTokenTtlMs ?? 72e5, "pageTokenTtlMs", 1),
4682
+ searchPageSize: integer(options.searchPageSize ?? PAGE_SIZE, "searchPageSize", 1, PAGE_SIZE),
4683
+ pendingAmbiguousWrites: 0,
4632
4684
  futureToleranceMs: options.futureToleranceMs === null ? null : integer(options.futureToleranceMs ?? 6e4, "futureToleranceMs")
4633
4685
  };
4634
4686
  this.state = new GoogleAdsState(
@@ -4643,9 +4695,11 @@ var GoogleAdsAPI = class {
4643
4695
  const wrap = (fn) => (c) => {
4644
4696
  try {
4645
4697
  if (c.request.signal.aborted) throw c.request.signal.reason;
4698
+ if (c.body.kind === "invalid" && !isMP(c.url.pathname))
4699
+ return rpcError(400, "Invalid JSON payload received.");
4646
4700
  return fn(c);
4647
4701
  } catch (e) {
4648
- if (e instanceof Rejection) return e.response(this.id(c.request));
4702
+ if (e instanceof Rejection) return this.rejected(e, c.request);
4649
4703
  throw e;
4650
4704
  }
4651
4705
  };
@@ -4676,13 +4730,22 @@ var GoogleAdsAPI = class {
4676
4730
  )
4677
4731
  ),
4678
4732
  MutateCampaignBudgets: wrap((c) => {
4679
- const body = record(c.body.kind === "json" ? c.body.value : void 0), result = this.ads.mutate(
4680
- present(c.params.customerId),
4681
- body,
4682
- this.id(c.request),
4683
- !!faultEffect(c.request, "partial_failure")
4684
- );
4685
- if (!body.validateOnly && faultEffect(c.request, "ambiguous_mutation"))
4733
+ const body = record(c.body.kind === "json" ? c.body.value : void 0), ambiguous = !!faultEffect(c.request, "ambiguous_mutation");
4734
+ let result;
4735
+ try {
4736
+ result = this.ads.mutate(
4737
+ present(c.params.customerId),
4738
+ body,
4739
+ this.id(c.request),
4740
+ !!faultEffect(c.request, "partial_failure")
4741
+ );
4742
+ } catch (e) {
4743
+ if (ambiguous) this.state.deferAmbiguousWrite();
4744
+ throw e;
4745
+ }
4746
+ if (body.validateOnly === true) {
4747
+ if (ambiguous) this.state.deferAmbiguousWrite();
4748
+ } else if (ambiguous || this.state.takeAmbiguousWrite())
4686
4749
  return rpcError(
4687
4750
  503,
4688
4751
  "Response unavailable after the budget mutation; reconcile before retrying"
@@ -4739,8 +4802,8 @@ var GoogleAdsAPI = class {
4739
4802
  const url = new URL(request.url);
4740
4803
  if (isMP(url.pathname))
4741
4804
  return this.collect(request, url, void 0, true, url.pathname.startsWith("/debug/"));
4742
- if (e instanceof Rejection) return e.response(this.id(request));
4743
- return rpcError(400, "Invalid JSON request body");
4805
+ if (e instanceof Rejection) return this.rejected(e, request);
4806
+ return rpcError(400, "Invalid JSON payload received.");
4744
4807
  }
4745
4808
  });
4746
4809
  this.app = this.service.app;
@@ -4753,6 +4816,10 @@ var GoogleAdsAPI = class {
4753
4816
  }
4754
4817
  return id;
4755
4818
  }
4819
+ /** Only Google Ads wraps a GoogleAdsFailure; the Analytics Data API answers a bare status. */
4820
+ rejected(e, request) {
4821
+ return isAds(new URL(request.url).pathname) ? e.response(this.id(request)) : e.plain();
4822
+ }
4756
4823
  authenticate(request) {
4757
4824
  const path = new URL(request.url).pathname;
4758
4825
  if (isMP(path)) return;
@@ -4823,10 +4890,10 @@ var GoogleAdsAPI = class {
4823
4890
  this.authenticate(request);
4824
4891
  response = await this.service.fetch(request);
4825
4892
  } catch (e) {
4826
- if (e instanceof Rejection) response = e.response(id);
4893
+ if (e instanceof Rejection) response = this.rejected(e, request);
4827
4894
  else throw e;
4828
4895
  }
4829
- if (url.pathname.startsWith("/v25/")) response.headers.set("request-id", id);
4896
+ if (isAds(url.pathname)) response.headers.set("request-id", id);
4830
4897
  return response;
4831
4898
  }
4832
4899
  collect(request, url, input, malformed = false, debug = false) {
@@ -4955,4 +5022,4 @@ export {
4955
5022
  DEFAULT_ADMIN_KEY,
4956
5023
  GoogleAdsAPI
4957
5024
  };
4958
- //# sourceMappingURL=chunk-DDJPMCRI.js.map
5025
+ //# sourceMappingURL=chunk-NU66LXUZ.js.map