thevoidforge 21.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.
- package/dist/scripts/vault-read.d.ts +11 -0
- package/dist/scripts/vault-read.js +89 -0
- package/dist/scripts/voidforge.d.ts +20 -0
- package/dist/scripts/voidforge.js +404 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/wizard/api/auth.d.ts +5 -0
- package/dist/wizard/api/auth.js +133 -0
- package/dist/wizard/api/blueprint.d.ts +45 -0
- package/dist/wizard/api/blueprint.js +184 -0
- package/dist/wizard/api/cloud-providers.d.ts +16 -0
- package/dist/wizard/api/cloud-providers.js +363 -0
- package/dist/wizard/api/credentials.d.ts +1 -0
- package/dist/wizard/api/credentials.js +258 -0
- package/dist/wizard/api/danger-room.d.ts +18 -0
- package/dist/wizard/api/danger-room.js +401 -0
- package/dist/wizard/api/deploy.d.ts +4 -0
- package/dist/wizard/api/deploy.js +164 -0
- package/dist/wizard/api/prd.d.ts +1 -0
- package/dist/wizard/api/prd.js +363 -0
- package/dist/wizard/api/project.d.ts +1 -0
- package/dist/wizard/api/project.js +239 -0
- package/dist/wizard/api/projects.d.ts +6 -0
- package/dist/wizard/api/projects.js +648 -0
- package/dist/wizard/api/provision.d.ts +4 -0
- package/dist/wizard/api/provision.js +535 -0
- package/dist/wizard/api/terminal.d.ts +25 -0
- package/dist/wizard/api/terminal.js +241 -0
- package/dist/wizard/api/users.d.ts +6 -0
- package/dist/wizard/api/users.js +244 -0
- package/dist/wizard/api/war-room.d.ts +14 -0
- package/dist/wizard/api/war-room.js +45 -0
- package/dist/wizard/lib/ad-platform-core.d.ts +6 -0
- package/dist/wizard/lib/ad-platform-core.js +1 -0
- package/dist/wizard/lib/adapters/index.d.ts +52 -0
- package/dist/wizard/lib/adapters/index.js +38 -0
- package/dist/wizard/lib/adapters/sandbox-bank.d.ts +17 -0
- package/dist/wizard/lib/adapters/sandbox-bank.js +77 -0
- package/dist/wizard/lib/adapters/sandbox.d.ts +39 -0
- package/dist/wizard/lib/adapters/sandbox.js +174 -0
- package/dist/wizard/lib/adapters/stripe.d.ts +19 -0
- package/dist/wizard/lib/adapters/stripe.js +143 -0
- package/dist/wizard/lib/adapters/types.d.ts +9 -0
- package/dist/wizard/lib/adapters/types.js +10 -0
- package/dist/wizard/lib/agent-memory.d.ts +36 -0
- package/dist/wizard/lib/agent-memory.js +114 -0
- package/dist/wizard/lib/anomaly-detection.d.ts +59 -0
- package/dist/wizard/lib/anomaly-detection.js +122 -0
- package/dist/wizard/lib/anthropic.d.ts +21 -0
- package/dist/wizard/lib/anthropic.js +105 -0
- package/dist/wizard/lib/asset-scanner.d.ts +23 -0
- package/dist/wizard/lib/asset-scanner.js +107 -0
- package/dist/wizard/lib/audit-log.d.ts +23 -0
- package/dist/wizard/lib/audit-log.js +70 -0
- package/dist/wizard/lib/autonomy-controller.d.ts +76 -0
- package/dist/wizard/lib/autonomy-controller.js +183 -0
- package/dist/wizard/lib/body-parser.d.ts +2 -0
- package/dist/wizard/lib/body-parser.js +36 -0
- package/dist/wizard/lib/build-analytics.d.ts +39 -0
- package/dist/wizard/lib/build-analytics.js +91 -0
- package/dist/wizard/lib/build-step.d.ts +21 -0
- package/dist/wizard/lib/build-step.js +104 -0
- package/dist/wizard/lib/campaign-proposer.d.ts +39 -0
- package/dist/wizard/lib/campaign-proposer.js +180 -0
- package/dist/wizard/lib/campaign-state-machine.d.ts +63 -0
- package/dist/wizard/lib/campaign-state-machine.js +114 -0
- package/dist/wizard/lib/ci-generator.d.ts +14 -0
- package/dist/wizard/lib/ci-generator.js +187 -0
- package/dist/wizard/lib/claude-merge.d.ts +38 -0
- package/dist/wizard/lib/claude-merge.js +115 -0
- package/dist/wizard/lib/codegen/erd-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/erd-gen.js +98 -0
- package/dist/wizard/lib/codegen/integrations.d.ts +18 -0
- package/dist/wizard/lib/codegen/integrations.js +189 -0
- package/dist/wizard/lib/codegen/openapi-gen.d.ts +15 -0
- package/dist/wizard/lib/codegen/openapi-gen.js +79 -0
- package/dist/wizard/lib/codegen/prisma-types.d.ts +15 -0
- package/dist/wizard/lib/codegen/prisma-types.js +44 -0
- package/dist/wizard/lib/codegen/seed-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/seed-gen.js +128 -0
- package/dist/wizard/lib/compliance.d.ts +51 -0
- package/dist/wizard/lib/compliance.js +112 -0
- package/dist/wizard/lib/correlation-engine.d.ts +59 -0
- package/dist/wizard/lib/correlation-engine.js +151 -0
- package/dist/wizard/lib/cost-estimator.d.ts +22 -0
- package/dist/wizard/lib/cost-estimator.js +72 -0
- package/dist/wizard/lib/cost-tracker.d.ts +27 -0
- package/dist/wizard/lib/cost-tracker.js +37 -0
- package/dist/wizard/lib/daemon-aggregator.d.ts +71 -0
- package/dist/wizard/lib/daemon-aggregator.js +204 -0
- package/dist/wizard/lib/daemon-core.d.ts +6 -0
- package/dist/wizard/lib/daemon-core.js +5 -0
- package/dist/wizard/lib/dashboard-data.d.ts +132 -0
- package/dist/wizard/lib/dashboard-data.js +336 -0
- package/dist/wizard/lib/dashboard-ws.d.ts +25 -0
- package/dist/wizard/lib/dashboard-ws.js +91 -0
- package/dist/wizard/lib/deep-current.d.ts +77 -0
- package/dist/wizard/lib/deep-current.js +234 -0
- package/dist/wizard/lib/deploy-coordinator.d.ts +40 -0
- package/dist/wizard/lib/deploy-coordinator.js +86 -0
- package/dist/wizard/lib/deploy-log.d.ts +28 -0
- package/dist/wizard/lib/deploy-log.js +52 -0
- package/dist/wizard/lib/desktop-notify.d.ts +27 -0
- package/dist/wizard/lib/desktop-notify.js +98 -0
- package/dist/wizard/lib/dns/cloudflare-dns.d.ts +35 -0
- package/dist/wizard/lib/dns/cloudflare-dns.js +216 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.d.ts +31 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.js +148 -0
- package/dist/wizard/lib/dns/types.d.ts +22 -0
- package/dist/wizard/lib/dns/types.js +4 -0
- package/dist/wizard/lib/document-discovery.d.ts +33 -0
- package/dist/wizard/lib/document-discovery.js +145 -0
- package/dist/wizard/lib/env-validator.d.ts +14 -0
- package/dist/wizard/lib/env-validator.js +205 -0
- package/dist/wizard/lib/env-writer.d.ts +13 -0
- package/dist/wizard/lib/env-writer.js +26 -0
- package/dist/wizard/lib/exec.d.ts +30 -0
- package/dist/wizard/lib/exec.js +52 -0
- package/dist/wizard/lib/experiment.d.ts +70 -0
- package/dist/wizard/lib/experiment.js +169 -0
- package/dist/wizard/lib/extensions.d.ts +20 -0
- package/dist/wizard/lib/extensions.js +183 -0
- package/dist/wizard/lib/financial/adapter-factory.d.ts +47 -0
- package/dist/wizard/lib/financial/adapter-factory.js +225 -0
- package/dist/wizard/lib/financial/billing/base.d.ts +6 -0
- package/dist/wizard/lib/financial/billing/base.js +1 -0
- package/dist/wizard/lib/financial/billing/google-billing.d.ts +56 -0
- package/dist/wizard/lib/financial/billing/google-billing.js +298 -0
- package/dist/wizard/lib/financial/billing/meta-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/meta-billing.js +243 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.js +260 -0
- package/dist/wizard/lib/financial/campaign/base.d.ts +13 -0
- package/dist/wizard/lib/financial/campaign/base.js +1 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.d.ts +42 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.js +388 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.d.ts +41 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.js +311 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.d.ts +45 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.js +261 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.d.ts +40 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.js +350 -0
- package/dist/wizard/lib/financial/funding-auto.d.ts +44 -0
- package/dist/wizard/lib/financial/funding-auto.js +52 -0
- package/dist/wizard/lib/financial/funding-policy.d.ts +60 -0
- package/dist/wizard/lib/financial/funding-policy.js +179 -0
- package/dist/wizard/lib/financial/platform-planner.d.ts +47 -0
- package/dist/wizard/lib/financial/platform-planner.js +134 -0
- package/dist/wizard/lib/financial/reconciliation-engine.d.ts +78 -0
- package/dist/wizard/lib/financial/reconciliation-engine.js +193 -0
- package/dist/wizard/lib/financial/registry.d.ts +22 -0
- package/dist/wizard/lib/financial/registry.js +26 -0
- package/dist/wizard/lib/financial/reporting.d.ts +96 -0
- package/dist/wizard/lib/financial/reporting.js +198 -0
- package/dist/wizard/lib/financial/stablecoin/base.d.ts +6 -0
- package/dist/wizard/lib/financial/stablecoin/base.js +1 -0
- package/dist/wizard/lib/financial/stablecoin/circle.d.ts +54 -0
- package/dist/wizard/lib/financial/stablecoin/circle.js +367 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.d.ts +24 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.js +171 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.d.ts +47 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.js +202 -0
- package/dist/wizard/lib/financial/treasury-planner.d.ts +52 -0
- package/dist/wizard/lib/financial/treasury-planner.js +128 -0
- package/dist/wizard/lib/financial-core.d.ts +6 -0
- package/dist/wizard/lib/financial-core.js +5 -0
- package/dist/wizard/lib/financial-vault.d.ts +34 -0
- package/dist/wizard/lib/financial-vault.js +199 -0
- package/dist/wizard/lib/frontmatter.d.ts +30 -0
- package/dist/wizard/lib/frontmatter.js +96 -0
- package/dist/wizard/lib/gap-analysis.d.ts +37 -0
- package/dist/wizard/lib/gap-analysis.js +218 -0
- package/dist/wizard/lib/github.d.ts +22 -0
- package/dist/wizard/lib/github.js +261 -0
- package/dist/wizard/lib/headless-deploy.d.ts +14 -0
- package/dist/wizard/lib/headless-deploy.js +452 -0
- package/dist/wizard/lib/health-monitor.d.ts +15 -0
- package/dist/wizard/lib/health-monitor.js +91 -0
- package/dist/wizard/lib/health-poller.d.ts +9 -0
- package/dist/wizard/lib/health-poller.js +123 -0
- package/dist/wizard/lib/heartbeat.d.ts +15 -0
- package/dist/wizard/lib/heartbeat.js +827 -0
- package/dist/wizard/lib/http-helpers.d.ts +9 -0
- package/dist/wizard/lib/http-helpers.js +24 -0
- package/dist/wizard/lib/image-gen.d.ts +56 -0
- package/dist/wizard/lib/image-gen.js +159 -0
- package/dist/wizard/lib/instance-sizing.d.ts +26 -0
- package/dist/wizard/lib/instance-sizing.js +51 -0
- package/dist/wizard/lib/kongo/analytics.d.ts +29 -0
- package/dist/wizard/lib/kongo/analytics.js +179 -0
- package/dist/wizard/lib/kongo/campaigns.d.ts +52 -0
- package/dist/wizard/lib/kongo/campaigns.js +91 -0
- package/dist/wizard/lib/kongo/client.d.ts +58 -0
- package/dist/wizard/lib/kongo/client.js +221 -0
- package/dist/wizard/lib/kongo/jobs.d.ts +57 -0
- package/dist/wizard/lib/kongo/jobs.js +122 -0
- package/dist/wizard/lib/kongo/pages.d.ts +60 -0
- package/dist/wizard/lib/kongo/pages.js +150 -0
- package/dist/wizard/lib/kongo/provisioner.d.ts +64 -0
- package/dist/wizard/lib/kongo/provisioner.js +116 -0
- package/dist/wizard/lib/kongo/seed.d.ts +49 -0
- package/dist/wizard/lib/kongo/seed.js +237 -0
- package/dist/wizard/lib/kongo/types.d.ts +323 -0
- package/dist/wizard/lib/kongo/types.js +11 -0
- package/dist/wizard/lib/kongo/variants.d.ts +57 -0
- package/dist/wizard/lib/kongo/variants.js +88 -0
- package/dist/wizard/lib/kongo/webhooks.d.ts +41 -0
- package/dist/wizard/lib/kongo/webhooks.js +112 -0
- package/dist/wizard/lib/marker.d.ts +28 -0
- package/dist/wizard/lib/marker.js +79 -0
- package/dist/wizard/lib/migrator.d.ts +35 -0
- package/dist/wizard/lib/migrator.js +190 -0
- package/dist/wizard/lib/natural-language-deploy.d.ts +30 -0
- package/dist/wizard/lib/natural-language-deploy.js +186 -0
- package/dist/wizard/lib/network.d.ts +22 -0
- package/dist/wizard/lib/network.js +72 -0
- package/dist/wizard/lib/oauth-core.d.ts +6 -0
- package/dist/wizard/lib/oauth-core.js +5 -0
- package/dist/wizard/lib/open-browser.d.ts +1 -0
- package/dist/wizard/lib/open-browser.js +26 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.d.ts +209 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.js +269 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.d.ts +200 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.js +212 -0
- package/dist/wizard/lib/patterns/daemon-process.d.ts +88 -0
- package/dist/wizard/lib/patterns/daemon-process.js +271 -0
- package/dist/wizard/lib/patterns/financial-transaction.d.ts +161 -0
- package/dist/wizard/lib/patterns/financial-transaction.js +132 -0
- package/dist/wizard/lib/patterns/funding-plan.d.ts +136 -0
- package/dist/wizard/lib/patterns/funding-plan.js +200 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.d.ts +94 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.js +139 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.d.ts +67 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.js +216 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.d.ts +96 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.js +182 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.d.ts +218 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.js +264 -0
- package/dist/wizard/lib/prd-validator.d.ts +39 -0
- package/dist/wizard/lib/prd-validator.js +137 -0
- package/dist/wizard/lib/project-init.d.ts +24 -0
- package/dist/wizard/lib/project-init.js +193 -0
- package/dist/wizard/lib/project-registry.d.ts +86 -0
- package/dist/wizard/lib/project-registry.js +359 -0
- package/dist/wizard/lib/provision-manifest.d.ts +44 -0
- package/dist/wizard/lib/provision-manifest.js +164 -0
- package/dist/wizard/lib/provisioner-registry.d.ts +15 -0
- package/dist/wizard/lib/provisioner-registry.js +34 -0
- package/dist/wizard/lib/provisioners/aws-vps.d.ts +6 -0
- package/dist/wizard/lib/provisioners/aws-vps.js +643 -0
- package/dist/wizard/lib/provisioners/cloudflare.d.ts +6 -0
- package/dist/wizard/lib/provisioners/cloudflare.js +300 -0
- package/dist/wizard/lib/provisioners/docker.d.ts +6 -0
- package/dist/wizard/lib/provisioners/docker.js +75 -0
- package/dist/wizard/lib/provisioners/http-client.d.ts +20 -0
- package/dist/wizard/lib/provisioners/http-client.js +79 -0
- package/dist/wizard/lib/provisioners/railway.d.ts +6 -0
- package/dist/wizard/lib/provisioners/railway.js +413 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.js +54 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.js +112 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.d.ts +11 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.js +91 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.d.ts +5 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.js +185 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.js +36 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.d.ts +14 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.js +202 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.js +67 -0
- package/dist/wizard/lib/provisioners/self-deploy.d.ts +41 -0
- package/dist/wizard/lib/provisioners/self-deploy.js +185 -0
- package/dist/wizard/lib/provisioners/static-s3.d.ts +6 -0
- package/dist/wizard/lib/provisioners/static-s3.js +235 -0
- package/dist/wizard/lib/provisioners/types.d.ts +40 -0
- package/dist/wizard/lib/provisioners/types.js +4 -0
- package/dist/wizard/lib/provisioners/vercel.d.ts +6 -0
- package/dist/wizard/lib/provisioners/vercel.js +287 -0
- package/dist/wizard/lib/pty-manager.d.ts +42 -0
- package/dist/wizard/lib/pty-manager.js +231 -0
- package/dist/wizard/lib/rate-limiter-core.d.ts +5 -0
- package/dist/wizard/lib/rate-limiter-core.js +5 -0
- package/dist/wizard/lib/reconciliation.d.ts +43 -0
- package/dist/wizard/lib/reconciliation.js +173 -0
- package/dist/wizard/lib/revenue-types.d.ts +5 -0
- package/dist/wizard/lib/revenue-types.js +1 -0
- package/dist/wizard/lib/route-optimizer.d.ts +28 -0
- package/dist/wizard/lib/route-optimizer.js +93 -0
- package/dist/wizard/lib/s3-deploy.d.ts +19 -0
- package/dist/wizard/lib/s3-deploy.js +156 -0
- package/dist/wizard/lib/safety-tiers.d.ts +76 -0
- package/dist/wizard/lib/safety-tiers.js +134 -0
- package/dist/wizard/lib/sentry-generator.d.ts +15 -0
- package/dist/wizard/lib/sentry-generator.js +116 -0
- package/dist/wizard/lib/server-config.d.ts +13 -0
- package/dist/wizard/lib/server-config.js +23 -0
- package/dist/wizard/lib/service-install.d.ts +18 -0
- package/dist/wizard/lib/service-install.js +182 -0
- package/dist/wizard/lib/site-scanner.d.ts +80 -0
- package/dist/wizard/lib/site-scanner.js +262 -0
- package/dist/wizard/lib/ssh-deploy.d.ts +25 -0
- package/dist/wizard/lib/ssh-deploy.js +225 -0
- package/dist/wizard/lib/templates.d.ts +24 -0
- package/dist/wizard/lib/templates.js +219 -0
- package/dist/wizard/lib/totp.d.ts +35 -0
- package/dist/wizard/lib/totp.js +276 -0
- package/dist/wizard/lib/tower-auth.d.ts +43 -0
- package/dist/wizard/lib/tower-auth.js +352 -0
- package/dist/wizard/lib/tower-rate-limit.d.ts +14 -0
- package/dist/wizard/lib/tower-rate-limit.js +61 -0
- package/dist/wizard/lib/tower-session.d.ts +28 -0
- package/dist/wizard/lib/tower-session.js +119 -0
- package/dist/wizard/lib/treasury-backup.d.ts +23 -0
- package/dist/wizard/lib/treasury-backup.js +126 -0
- package/dist/wizard/lib/treasury-heartbeat.d.ts +82 -0
- package/dist/wizard/lib/treasury-heartbeat.js +1104 -0
- package/dist/wizard/lib/updater.d.ts +29 -0
- package/dist/wizard/lib/updater.js +190 -0
- package/dist/wizard/lib/user-manager.d.ts +39 -0
- package/dist/wizard/lib/user-manager.js +182 -0
- package/dist/wizard/lib/vault.d.ts +26 -0
- package/dist/wizard/lib/vault.js +161 -0
- package/dist/wizard/router.d.ts +5 -0
- package/dist/wizard/router.js +15 -0
- package/dist/wizard/server.d.ts +18 -0
- package/dist/wizard/server.js +436 -0
- package/package.json +59 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Ads Campaign Adapter — real implementation via node:https (zero new dependencies).
|
|
3
|
+
*
|
|
4
|
+
* Implements AdPlatformAdapter for Google Ads API v17.
|
|
5
|
+
*
|
|
6
|
+
* Google Ads API v17:
|
|
7
|
+
* Base URL: https://googleads.googleapis.com/v17
|
|
8
|
+
* Auth: Authorization: Bearer {accessToken} + developer-token header
|
|
9
|
+
* Campaign CRUD via mutate endpoints
|
|
10
|
+
* Reporting via searchStream
|
|
11
|
+
* Rate limit: 15,000 operations/day
|
|
12
|
+
*
|
|
13
|
+
* PRD Reference: §9.5, §9.19.10, §9.20.4
|
|
14
|
+
* No Stubs Doctrine: every method makes a real API call or returns documented empty.
|
|
15
|
+
*/
|
|
16
|
+
import { request as httpsRequest } from 'node:https';
|
|
17
|
+
import { toCents, TokenBucketLimiter } from './base.js';
|
|
18
|
+
const GOOGLE_ADS_HOST = 'googleads.googleapis.com';
|
|
19
|
+
// ── HTTP helpers ─────────────────────────────────────
|
|
20
|
+
async function googleGet(path, accessToken, developerToken) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const req = httpsRequest({
|
|
23
|
+
hostname: GOOGLE_ADS_HOST,
|
|
24
|
+
path: `/v17${path}`,
|
|
25
|
+
method: 'GET',
|
|
26
|
+
headers: {
|
|
27
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
28
|
+
'developer-token': developerToken,
|
|
29
|
+
'Accept': 'application/json',
|
|
30
|
+
},
|
|
31
|
+
timeout: 15000,
|
|
32
|
+
}, (res) => {
|
|
33
|
+
let data = '';
|
|
34
|
+
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
35
|
+
res.on('end', () => resolve({ status: res.statusCode ?? 500, body: data }));
|
|
36
|
+
});
|
|
37
|
+
req.on('error', reject);
|
|
38
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Google Ads API timeout')); });
|
|
39
|
+
req.end();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async function googlePost(path, accessToken, developerToken, body) {
|
|
43
|
+
const payload = JSON.stringify(body);
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const req = httpsRequest({
|
|
46
|
+
hostname: GOOGLE_ADS_HOST,
|
|
47
|
+
path: `/v17${path}`,
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
51
|
+
'developer-token': developerToken,
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
'Accept': 'application/json',
|
|
54
|
+
},
|
|
55
|
+
timeout: 15000,
|
|
56
|
+
}, (res) => {
|
|
57
|
+
let data = '';
|
|
58
|
+
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
59
|
+
res.on('end', () => resolve({ status: res.statusCode ?? 500, body: data }));
|
|
60
|
+
});
|
|
61
|
+
req.on('error', reject);
|
|
62
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Google Ads API timeout')); });
|
|
63
|
+
req.write(payload);
|
|
64
|
+
req.end();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function safeParseJson(body) {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(body);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return { error: { message: 'Non-JSON response from Google Ads API' } };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Sanitize GAQL parameter — allow only alphanumeric, underscores, hyphens, dots. */
|
|
76
|
+
function sanitizeGaqlParam(value) {
|
|
77
|
+
return value.replace(/[^a-zA-Z0-9_.\-]/g, '');
|
|
78
|
+
}
|
|
79
|
+
/** Sanitize a date string for GAQL — must be YYYY-MM-DD. */
|
|
80
|
+
function sanitizeDate(value) {
|
|
81
|
+
const match = value.match(/^(\d{4}-\d{2}-\d{2})/);
|
|
82
|
+
return match ? match[1] : new Date().toISOString().slice(0, 10);
|
|
83
|
+
}
|
|
84
|
+
function makePlatformError(code, originalCode, message, retryable = false, retryAfter) {
|
|
85
|
+
return { platform: 'google', code, originalCode, message, retryable, retryAfter };
|
|
86
|
+
}
|
|
87
|
+
// ── Adapter Implementation ──────────────────────────
|
|
88
|
+
export class GoogleCampaignAdapter {
|
|
89
|
+
config;
|
|
90
|
+
rateLimiter;
|
|
91
|
+
constructor(config) {
|
|
92
|
+
this.config = config;
|
|
93
|
+
// Google Ads: 15,000 operations/day ≈ 0.17/sec
|
|
94
|
+
this.rateLimiter = new TokenBucketLimiter({ capacity: 100, refillRate: 15000 / 86400 });
|
|
95
|
+
}
|
|
96
|
+
async refreshToken(token) {
|
|
97
|
+
// Google OAuth2 token refresh via googleapis.com
|
|
98
|
+
const payload = JSON.stringify({
|
|
99
|
+
client_id: 'configured-in-vault',
|
|
100
|
+
grant_type: 'refresh_token',
|
|
101
|
+
refresh_token: token.refreshToken,
|
|
102
|
+
});
|
|
103
|
+
const result = await new Promise((resolve, reject) => {
|
|
104
|
+
const req = httpsRequest({
|
|
105
|
+
hostname: 'oauth2.googleapis.com',
|
|
106
|
+
path: '/token',
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: { 'Content-Type': 'application/json' },
|
|
109
|
+
timeout: 10000,
|
|
110
|
+
}, (res) => {
|
|
111
|
+
let data = '';
|
|
112
|
+
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
113
|
+
res.on('end', () => resolve({ status: res.statusCode ?? 500, body: data }));
|
|
114
|
+
});
|
|
115
|
+
req.on('error', reject);
|
|
116
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Google OAuth timeout')); });
|
|
117
|
+
req.write(payload);
|
|
118
|
+
req.end();
|
|
119
|
+
});
|
|
120
|
+
if (result.status !== 200) {
|
|
121
|
+
throw makePlatformError('AUTH_EXPIRED', result.status, 'Google token refresh failed');
|
|
122
|
+
}
|
|
123
|
+
const parsed = safeParseJson(result.body);
|
|
124
|
+
return {
|
|
125
|
+
...token,
|
|
126
|
+
accessToken: parsed.access_token,
|
|
127
|
+
expiresAt: new Date(Date.now() + (parsed.expires_in ?? 3600) * 1000).toISOString(),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async createCampaign(config) {
|
|
131
|
+
if (config.complianceStatus !== 'passed') {
|
|
132
|
+
throw makePlatformError('UNKNOWN', 400, 'Campaign compliance not passed — cannot create');
|
|
133
|
+
}
|
|
134
|
+
await this.rateLimiter.acquire();
|
|
135
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/campaigns:mutate`, this.config.accessToken, this.config.developerToken, {
|
|
136
|
+
operations: [{
|
|
137
|
+
create: {
|
|
138
|
+
name: config.name,
|
|
139
|
+
advertisingChannelType: 'SEARCH',
|
|
140
|
+
status: 'PAUSED',
|
|
141
|
+
campaignBudget: `customers/${this.config.customerId}/campaignBudgets/-1`,
|
|
142
|
+
biddingStrategyType: config.objective === 'conversions' ? 'MAXIMIZE_CONVERSIONS' : 'MAXIMIZE_CLICKS',
|
|
143
|
+
},
|
|
144
|
+
}],
|
|
145
|
+
// Idempotency: Google uses request IDs
|
|
146
|
+
requestId: config.idempotencyKey,
|
|
147
|
+
});
|
|
148
|
+
if (status !== 200) {
|
|
149
|
+
this.throwApiError(status, body);
|
|
150
|
+
}
|
|
151
|
+
const parsed = safeParseJson(body);
|
|
152
|
+
const results = parsed.results ?? [];
|
|
153
|
+
const campaignResource = results[0]?.resourceName ?? '';
|
|
154
|
+
const externalId = campaignResource.split('/').pop() ?? '';
|
|
155
|
+
return {
|
|
156
|
+
externalId,
|
|
157
|
+
platform: 'google',
|
|
158
|
+
status: 'created',
|
|
159
|
+
dashboardUrl: `https://ads.google.com/aw/campaigns?campaignId=${externalId}&ocid=${this.config.customerId}`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
async updateCampaign(id, changes) {
|
|
163
|
+
await this.rateLimiter.acquire();
|
|
164
|
+
const update = {
|
|
165
|
+
resourceName: `customers/${this.config.customerId}/campaigns/${id}`,
|
|
166
|
+
};
|
|
167
|
+
const updateMask = [];
|
|
168
|
+
if (changes.name !== undefined) {
|
|
169
|
+
update.name = changes.name;
|
|
170
|
+
updateMask.push('name');
|
|
171
|
+
}
|
|
172
|
+
if (updateMask.length === 0)
|
|
173
|
+
return;
|
|
174
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/campaigns:mutate`, this.config.accessToken, this.config.developerToken, { operations: [{ update, updateMask: updateMask.join(',') }] });
|
|
175
|
+
if (status !== 200) {
|
|
176
|
+
this.throwApiError(status, body);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async pauseCampaign(id) {
|
|
180
|
+
await this.rateLimiter.acquire();
|
|
181
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/campaigns:mutate`, this.config.accessToken, this.config.developerToken, {
|
|
182
|
+
operations: [{
|
|
183
|
+
update: {
|
|
184
|
+
resourceName: `customers/${this.config.customerId}/campaigns/${id}`,
|
|
185
|
+
status: 'PAUSED',
|
|
186
|
+
},
|
|
187
|
+
updateMask: 'status',
|
|
188
|
+
}],
|
|
189
|
+
});
|
|
190
|
+
if (status !== 200) {
|
|
191
|
+
this.throwApiError(status, body);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async resumeCampaign(id) {
|
|
195
|
+
await this.rateLimiter.acquire();
|
|
196
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/campaigns:mutate`, this.config.accessToken, this.config.developerToken, {
|
|
197
|
+
operations: [{
|
|
198
|
+
update: {
|
|
199
|
+
resourceName: `customers/${this.config.customerId}/campaigns/${id}`,
|
|
200
|
+
status: 'ENABLED',
|
|
201
|
+
},
|
|
202
|
+
updateMask: 'status',
|
|
203
|
+
}],
|
|
204
|
+
});
|
|
205
|
+
if (status !== 200) {
|
|
206
|
+
this.throwApiError(status, body);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async deleteCampaign(id) {
|
|
210
|
+
await this.rateLimiter.acquire();
|
|
211
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/campaigns:mutate`, this.config.accessToken, this.config.developerToken, {
|
|
212
|
+
operations: [{
|
|
213
|
+
remove: `customers/${this.config.customerId}/campaigns/${id}`,
|
|
214
|
+
}],
|
|
215
|
+
});
|
|
216
|
+
if (status !== 200) {
|
|
217
|
+
this.throwApiError(status, body);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async updateBudget(id, dailyBudget) {
|
|
221
|
+
await this.rateLimiter.acquire();
|
|
222
|
+
// Google budgets are in micros (1/1,000,000 of currency unit)
|
|
223
|
+
// cents → dollars → micros: dailyBudget / 100 * 1,000,000 = dailyBudget * 10,000
|
|
224
|
+
const budgetMicros = dailyBudget * 10000;
|
|
225
|
+
// First, query the campaign's budget resource
|
|
226
|
+
const queryResult = await googlePost(`/customers/${this.config.customerId}/googleAds:searchStream`, this.config.accessToken, this.config.developerToken, {
|
|
227
|
+
query: `SELECT campaign_budget.resource_name FROM campaign WHERE campaign.id = ${sanitizeGaqlParam(id)} LIMIT 1`,
|
|
228
|
+
});
|
|
229
|
+
if (queryResult.status !== 200) {
|
|
230
|
+
this.throwApiError(queryResult.status, queryResult.body);
|
|
231
|
+
}
|
|
232
|
+
const queryParsed = safeParseJson(queryResult.body);
|
|
233
|
+
const queryResults = queryParsed;
|
|
234
|
+
const budgetResource = queryResults[0]?.results?.[0]?.campaignBudget?.resourceName;
|
|
235
|
+
if (!budgetResource) {
|
|
236
|
+
throw makePlatformError('UNKNOWN', 404, `Budget resource not found for campaign ${id}`);
|
|
237
|
+
}
|
|
238
|
+
// Then update the budget
|
|
239
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/campaignBudgets:mutate`, this.config.accessToken, this.config.developerToken, {
|
|
240
|
+
operations: [{
|
|
241
|
+
update: {
|
|
242
|
+
resourceName: budgetResource,
|
|
243
|
+
amountMicros: budgetMicros,
|
|
244
|
+
},
|
|
245
|
+
updateMask: 'amount_micros',
|
|
246
|
+
}],
|
|
247
|
+
});
|
|
248
|
+
if (status !== 200) {
|
|
249
|
+
this.throwApiError(status, body);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async updateCreative(id, creative) {
|
|
253
|
+
await this.rateLimiter.acquire();
|
|
254
|
+
// Google creative updates go through ad groups and ads, not campaigns directly.
|
|
255
|
+
// Query the first ad group under this campaign, then update its ad.
|
|
256
|
+
const queryResult = await googlePost(`/customers/${this.config.customerId}/googleAds:searchStream`, this.config.accessToken, this.config.developerToken, {
|
|
257
|
+
query: `SELECT ad_group_ad.ad.resource_name, ad_group_ad.ad.id FROM ad_group_ad WHERE campaign.id = ${sanitizeGaqlParam(id)} LIMIT 1`,
|
|
258
|
+
});
|
|
259
|
+
if (queryResult.status !== 200) {
|
|
260
|
+
this.throwApiError(queryResult.status, queryResult.body);
|
|
261
|
+
}
|
|
262
|
+
const queryParsed = safeParseJson(queryResult.body);
|
|
263
|
+
const queryResults = queryParsed;
|
|
264
|
+
const adResource = queryResults[0]?.results?.[0]?.adGroupAd?.ad?.resourceName;
|
|
265
|
+
if (!adResource) {
|
|
266
|
+
throw makePlatformError('CREATIVE_REJECTED', 404, `No ad found for campaign ${id}`);
|
|
267
|
+
}
|
|
268
|
+
const update = { resourceName: adResource };
|
|
269
|
+
const updateMask = [];
|
|
270
|
+
if (creative.headlines) {
|
|
271
|
+
update.responsiveSearchAd = {
|
|
272
|
+
...(update.responsiveSearchAd ?? {}),
|
|
273
|
+
headlines: creative.headlines.map(h => ({ text: h })),
|
|
274
|
+
};
|
|
275
|
+
updateMask.push('responsive_search_ad.headlines');
|
|
276
|
+
}
|
|
277
|
+
if (creative.descriptions) {
|
|
278
|
+
update.responsiveSearchAd = {
|
|
279
|
+
...(update.responsiveSearchAd ?? {}),
|
|
280
|
+
descriptions: creative.descriptions.map(d => ({ text: d })),
|
|
281
|
+
};
|
|
282
|
+
updateMask.push('responsive_search_ad.descriptions');
|
|
283
|
+
}
|
|
284
|
+
if (creative.landingUrl) {
|
|
285
|
+
update.finalUrls = [creative.landingUrl];
|
|
286
|
+
updateMask.push('final_urls');
|
|
287
|
+
}
|
|
288
|
+
if (updateMask.length === 0)
|
|
289
|
+
return;
|
|
290
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/ads:mutate`, this.config.accessToken, this.config.developerToken, { operations: [{ update, updateMask: updateMask.join(',') }] });
|
|
291
|
+
if (status !== 200) {
|
|
292
|
+
this.throwApiError(status, body);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async getSpend(dateRange) {
|
|
296
|
+
await this.rateLimiter.acquire();
|
|
297
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/googleAds:searchStream`, this.config.accessToken, this.config.developerToken, {
|
|
298
|
+
query: [
|
|
299
|
+
'SELECT campaign.id, metrics.cost_micros, metrics.impressions,',
|
|
300
|
+
'metrics.clicks, metrics.conversions',
|
|
301
|
+
'FROM campaign',
|
|
302
|
+
`WHERE segments.date BETWEEN '${sanitizeDate(dateRange.start)}' AND '${sanitizeDate(dateRange.end)}'`,
|
|
303
|
+
].join(' '),
|
|
304
|
+
});
|
|
305
|
+
if (status !== 200) {
|
|
306
|
+
this.throwApiError(status, body);
|
|
307
|
+
}
|
|
308
|
+
const parsed = safeParseJson(body);
|
|
309
|
+
const results = parsed;
|
|
310
|
+
const rows = results[0]?.results ?? [];
|
|
311
|
+
const campaigns = rows.map(row => ({
|
|
312
|
+
externalId: row.campaign?.id ?? '',
|
|
313
|
+
spend: toCents(parseInt(row.metrics?.costMicros ?? '0') / 1_000_000),
|
|
314
|
+
impressions: parseInt(row.metrics?.impressions ?? '0'),
|
|
315
|
+
clicks: parseInt(row.metrics?.clicks ?? '0'),
|
|
316
|
+
conversions: Math.round(parseFloat(row.metrics?.conversions ?? '0')),
|
|
317
|
+
}));
|
|
318
|
+
const totalSpend = campaigns.reduce((sum, c) => (sum + c.spend), 0);
|
|
319
|
+
return { platform: 'google', dateRange, totalSpend, campaigns };
|
|
320
|
+
}
|
|
321
|
+
async getPerformance(campaignId) {
|
|
322
|
+
await this.rateLimiter.acquire();
|
|
323
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
324
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/googleAds:searchStream`, this.config.accessToken, this.config.developerToken, {
|
|
325
|
+
query: [
|
|
326
|
+
'SELECT metrics.cost_micros, metrics.impressions, metrics.clicks,',
|
|
327
|
+
'metrics.conversions, metrics.ctr, metrics.average_cpc',
|
|
328
|
+
'FROM campaign',
|
|
329
|
+
`WHERE campaign.id = ${sanitizeGaqlParam(campaignId)}`,
|
|
330
|
+
`AND segments.date = '${today}'`,
|
|
331
|
+
].join(' '),
|
|
332
|
+
});
|
|
333
|
+
if (status !== 200) {
|
|
334
|
+
this.throwApiError(status, body);
|
|
335
|
+
}
|
|
336
|
+
const parsed = safeParseJson(body);
|
|
337
|
+
const results = parsed;
|
|
338
|
+
const m = results[0]?.results?.[0]?.metrics ?? {};
|
|
339
|
+
const spend = toCents(parseInt(m.costMicros ?? '0') / 1_000_000);
|
|
340
|
+
const impressions = parseInt(m.impressions ?? '0');
|
|
341
|
+
const clicks = parseInt(m.clicks ?? '0');
|
|
342
|
+
const conversions = Math.round(parseFloat(m.conversions ?? '0'));
|
|
343
|
+
return {
|
|
344
|
+
campaignId,
|
|
345
|
+
impressions,
|
|
346
|
+
clicks,
|
|
347
|
+
conversions,
|
|
348
|
+
spend,
|
|
349
|
+
ctr: parseFloat(m.ctr ?? '0'),
|
|
350
|
+
cpc: toCents(parseInt(m.averageCpc ?? '0') / 1_000_000),
|
|
351
|
+
roas: (spend > 0 ? 0 : 0), // Revenue from Stripe, not ad platform
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
async getInsights(campaignId, metrics) {
|
|
355
|
+
await this.rateLimiter.acquire();
|
|
356
|
+
const metricsQuery = metrics.map(m => `metrics.${sanitizeGaqlParam(m)}`).join(', ');
|
|
357
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
358
|
+
const { status, body } = await googlePost(`/customers/${this.config.customerId}/googleAds:searchStream`, this.config.accessToken, this.config.developerToken, {
|
|
359
|
+
query: `SELECT ${metricsQuery} FROM campaign WHERE campaign.id = ${sanitizeGaqlParam(campaignId)} AND segments.date = '${today}'`,
|
|
360
|
+
});
|
|
361
|
+
if (status !== 200) {
|
|
362
|
+
this.throwApiError(status, body);
|
|
363
|
+
}
|
|
364
|
+
const parsed = safeParseJson(body);
|
|
365
|
+
const results = parsed;
|
|
366
|
+
const row = results[0]?.results?.[0]?.metrics ?? {};
|
|
367
|
+
const result = {};
|
|
368
|
+
for (const metric of metrics) {
|
|
369
|
+
result[metric] = parseFloat(row[metric] ?? '0');
|
|
370
|
+
}
|
|
371
|
+
return { campaignId, metrics: result };
|
|
372
|
+
}
|
|
373
|
+
// ── Private helpers ─────────────────────────────────
|
|
374
|
+
throwApiError(status, body) {
|
|
375
|
+
const parsed = safeParseJson(body);
|
|
376
|
+
const errMsg = parsed.error?.message ?? `HTTP ${status}`;
|
|
377
|
+
if (status === 429) {
|
|
378
|
+
throw makePlatformError('RATE_LIMITED', status, errMsg, true, 60);
|
|
379
|
+
}
|
|
380
|
+
if (status === 401 || status === 403) {
|
|
381
|
+
throw makePlatformError('AUTH_EXPIRED', status, errMsg);
|
|
382
|
+
}
|
|
383
|
+
if (errMsg.toLowerCase().includes('budget') || errMsg.includes('BudgetError')) {
|
|
384
|
+
throw makePlatformError('BUDGET_EXCEEDED', status, errMsg);
|
|
385
|
+
}
|
|
386
|
+
throw makePlatformError('UNKNOWN', status, errMsg);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta Marketing Campaign Adapter — real implementation via node:https (zero new dependencies).
|
|
3
|
+
*
|
|
4
|
+
* Implements AdPlatformAdapter for Meta Marketing API v19.0.
|
|
5
|
+
*
|
|
6
|
+
* Meta Marketing API v19.0:
|
|
7
|
+
* Base URL: https://graph.facebook.com/v19.0
|
|
8
|
+
* Auth: access_token query parameter
|
|
9
|
+
* Campaign CRUD via Graph API
|
|
10
|
+
* Reporting via insights endpoint
|
|
11
|
+
* Rate limit: 200 calls/hr/ad account (sliding window)
|
|
12
|
+
*
|
|
13
|
+
* PRD Reference: §9.5, §9.19.10, §9.20.4
|
|
14
|
+
* No Stubs Doctrine: every method makes a real API call or returns documented empty.
|
|
15
|
+
*/
|
|
16
|
+
import type { AdPlatformAdapter, CampaignConfig, CampaignResult, CampaignUpdate, CreativeConfig, SpendReport, PerformanceMetrics, InsightData, OAuthTokens, Cents } from './base.js';
|
|
17
|
+
interface MetaCampaignConfig {
|
|
18
|
+
adAccountId: string;
|
|
19
|
+
accessToken: string;
|
|
20
|
+
}
|
|
21
|
+
export declare class MetaCampaignAdapter implements AdPlatformAdapter {
|
|
22
|
+
private readonly config;
|
|
23
|
+
private readonly rateLimiter;
|
|
24
|
+
constructor(config: MetaCampaignConfig);
|
|
25
|
+
refreshToken(token: OAuthTokens): Promise<OAuthTokens>;
|
|
26
|
+
createCampaign(config: CampaignConfig): Promise<CampaignResult>;
|
|
27
|
+
updateCampaign(id: string, changes: CampaignUpdate): Promise<void>;
|
|
28
|
+
pauseCampaign(id: string): Promise<void>;
|
|
29
|
+
resumeCampaign(id: string): Promise<void>;
|
|
30
|
+
deleteCampaign(id: string): Promise<void>;
|
|
31
|
+
updateBudget(id: string, dailyBudget: Cents): Promise<void>;
|
|
32
|
+
updateCreative(id: string, creative: CreativeConfig): Promise<void>;
|
|
33
|
+
getSpend(dateRange: {
|
|
34
|
+
start: string;
|
|
35
|
+
end: string;
|
|
36
|
+
}): Promise<SpendReport>;
|
|
37
|
+
getPerformance(campaignId: string): Promise<PerformanceMetrics>;
|
|
38
|
+
getInsights(campaignId: string, metrics: string[]): Promise<InsightData>;
|
|
39
|
+
private throwApiError;
|
|
40
|
+
}
|
|
41
|
+
export {};
|