@adport/provider-apple 0.3.0 → 0.4.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/index.d.ts +14 -1
- package/dist/index.js +220 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ declare class AppleAdsClient {
|
|
|
39
39
|
constructor(credentials: AppleCredentials, fetchImpl?: typeof fetch);
|
|
40
40
|
getAccessToken(): Promise<string>;
|
|
41
41
|
/** orgId (as X-AP-Context) is required on all endpoints except /acls and /me. */
|
|
42
|
-
request<T>(method: 'GET' | 'POST' | 'PUT', path: string, options?: {
|
|
42
|
+
request<T>(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, options?: {
|
|
43
43
|
orgId?: string;
|
|
44
44
|
body?: unknown;
|
|
45
45
|
}): Promise<AppleEnvelope<T>>;
|
|
@@ -94,6 +94,16 @@ declare class AppleAdsProvider implements AdProvider {
|
|
|
94
94
|
listAccounts(): Promise<Account[]>;
|
|
95
95
|
listCampaigns(orgId: string, limit?: number): Promise<AppleCampaign[]>;
|
|
96
96
|
getCampaign(orgId: string, campaignId: string): Promise<AppleCampaign>;
|
|
97
|
+
/**
|
|
98
|
+
* Safe low-level access to the documented read surface. Apple uses POST for
|
|
99
|
+
* selectors and reports, so method alone cannot determine mutability.
|
|
100
|
+
*/
|
|
101
|
+
apiRead(input: {
|
|
102
|
+
account_id?: string;
|
|
103
|
+
method: 'GET' | 'POST';
|
|
104
|
+
path: string;
|
|
105
|
+
body?: Record<string, unknown>;
|
|
106
|
+
}): Promise<unknown>;
|
|
97
107
|
report(query: NormalizedQuery): Promise<Report>;
|
|
98
108
|
private toReportRow;
|
|
99
109
|
previewWrite(op: WriteOperation, guard: WriteGuard): Promise<WritePreview>;
|
|
@@ -102,6 +112,9 @@ declare class AppleAdsProvider implements AdProvider {
|
|
|
102
112
|
private planCreateCampaign;
|
|
103
113
|
private planSetStatus;
|
|
104
114
|
private planSetBudget;
|
|
115
|
+
private planApiCreate;
|
|
116
|
+
private planApiUpdate;
|
|
117
|
+
private planApiDelete;
|
|
105
118
|
}
|
|
106
119
|
|
|
107
120
|
declare function appleTools(provider: AppleAdsProvider): AnyToolDefinition[];
|
package/dist/index.js
CHANGED
|
@@ -106,6 +106,8 @@ import {
|
|
|
106
106
|
resolveDateRange
|
|
107
107
|
} from "@adport/core";
|
|
108
108
|
var UNITS_TO_MICROS = 1e6;
|
|
109
|
+
var APPLE_READ_ROOTS = /^(?:acls|me|apps(?:\/.*)?|campaigns(?:\/.*)?|adgroups(?:\/.*)?|targetingkeywords(?:\/.*)?|negativekeywords(?:\/.*)?|ads(?:\/.*)?|creatives(?:\/.*)?|product-pages(?:\/.*)?|search(?:\/.*)?|geolocations(?:\/.*)?|budgetorders(?:\/.*)?|reports(?:\/.*)?|customreports(?:\/.*)?)(?:\?.*)?$/;
|
|
110
|
+
var APPLE_MUTATION_ROOTS = /^(?:campaigns|adgroups|targetingkeywords|negativekeywords|ads|creatives|budgetorders)(?:\/[^?#]+)*$/;
|
|
109
111
|
var AppleAdsProvider = class {
|
|
110
112
|
constructor(client) {
|
|
111
113
|
this.client = client;
|
|
@@ -154,6 +156,27 @@ var AppleAdsProvider = class {
|
|
|
154
156
|
}
|
|
155
157
|
return campaign;
|
|
156
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Safe low-level access to the documented read surface. Apple uses POST for
|
|
161
|
+
* selectors and reports, so method alone cannot determine mutability.
|
|
162
|
+
*/
|
|
163
|
+
async apiRead(input) {
|
|
164
|
+
const path = normalizeApiPath(input.path);
|
|
165
|
+
if (!APPLE_READ_ROOTS.test(path)) {
|
|
166
|
+
throw new AdportError2("INVALID_INPUT", `apple: unsupported read path "${path}"`);
|
|
167
|
+
}
|
|
168
|
+
if (input.method === "POST" && !path.includes("/find") && !path.startsWith("reports/") && !path.startsWith("customreports")) {
|
|
169
|
+
throw new AdportError2(
|
|
170
|
+
"INVALID_INPUT",
|
|
171
|
+
"apple: POST is read-only here only for /find, reports/*, and customreports endpoints"
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const envelope = await this.client.request(input.method, path, {
|
|
175
|
+
...input.account_id ? { orgId: input.account_id } : {},
|
|
176
|
+
...input.body ? { body: input.body } : {}
|
|
177
|
+
});
|
|
178
|
+
return envelope;
|
|
179
|
+
}
|
|
157
180
|
async report(query) {
|
|
158
181
|
if (query.level !== "campaign" && query.level !== "account") {
|
|
159
182
|
throw new AdportError2("INVALID_INPUT", "apple: report supports campaign and account levels in v0");
|
|
@@ -181,8 +204,13 @@ var AppleAdsProvider = class {
|
|
|
181
204
|
}
|
|
182
205
|
}
|
|
183
206
|
);
|
|
184
|
-
|
|
185
|
-
|
|
207
|
+
const providerRows = (envelope.data?.reportingDataResponse?.row ?? []).map(
|
|
208
|
+
(row) => this.toReportRow(row, orgId, query)
|
|
209
|
+
);
|
|
210
|
+
if (query.level === "account") {
|
|
211
|
+
if (providerRows.length > 0) rows.push(aggregateAccountRows(providerRows, this.id, orgId));
|
|
212
|
+
} else {
|
|
213
|
+
rows.push(...providerRows);
|
|
186
214
|
}
|
|
187
215
|
}
|
|
188
216
|
return { rows };
|
|
@@ -241,6 +269,12 @@ var AppleAdsProvider = class {
|
|
|
241
269
|
return this.planSetStatus(op.accountId, payload);
|
|
242
270
|
case "apple_set_budget":
|
|
243
271
|
return this.planSetBudget(op.accountId, payload);
|
|
272
|
+
case "apple_api_create":
|
|
273
|
+
return this.planApiCreate(op.accountId, payload, guard);
|
|
274
|
+
case "apple_api_update":
|
|
275
|
+
return this.planApiUpdate(op.accountId, payload);
|
|
276
|
+
case "apple_api_delete":
|
|
277
|
+
return this.planApiDelete(op.accountId, payload);
|
|
244
278
|
default:
|
|
245
279
|
throw new AdportError2("PROVIDER_ERROR", `apple: unsupported write tool ${op.tool}`);
|
|
246
280
|
}
|
|
@@ -318,7 +352,145 @@ var AppleAdsProvider = class {
|
|
|
318
352
|
}
|
|
319
353
|
};
|
|
320
354
|
}
|
|
355
|
+
async planApiCreate(orgId, payload, guard) {
|
|
356
|
+
const path = validateMutationPath(payload.path);
|
|
357
|
+
const body = structuredClone(payload.body);
|
|
358
|
+
const coercions = [];
|
|
359
|
+
if (guard.forcePausedCreation) coerceCreatedStatuses(body, coercions);
|
|
360
|
+
const budgetDeltas = collectCreatedMoney(body);
|
|
361
|
+
return {
|
|
362
|
+
summary: `Create Apple Ads resource via POST /${path}`,
|
|
363
|
+
changes: [`+ POST /${path} ${JSON.stringify(body)}`],
|
|
364
|
+
coercions,
|
|
365
|
+
budgetDeltas,
|
|
366
|
+
execute: async () => {
|
|
367
|
+
const envelope = await this.client.request("POST", path, { orgId, body });
|
|
368
|
+
return extractResourceIds(envelope.data);
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
async planApiUpdate(orgId, payload) {
|
|
373
|
+
const path = validateMutationPath(payload.path);
|
|
374
|
+
if (containsMoneyField(payload.body)) {
|
|
375
|
+
throw new AdportError2(
|
|
376
|
+
"INVALID_INPUT",
|
|
377
|
+
"apple: monetary updates require a typed budget or bid tool so current and proposed values can be policy-checked"
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
summary: `Update Apple Ads resource via PUT /${path}`,
|
|
382
|
+
changes: [`~ PUT /${path} ${JSON.stringify(payload.body)}`],
|
|
383
|
+
coercions: [],
|
|
384
|
+
budgetDeltas: [],
|
|
385
|
+
execute: async () => {
|
|
386
|
+
const envelope = await this.client.request("PUT", path, { orgId, body: payload.body });
|
|
387
|
+
return extractResourceIds(envelope.data, path);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
async planApiDelete(orgId, payload) {
|
|
392
|
+
const path = validateMutationPath(payload.path);
|
|
393
|
+
return {
|
|
394
|
+
summary: `Delete Apple Ads resource via DELETE /${path}`,
|
|
395
|
+
changes: [`- DELETE /${path}`],
|
|
396
|
+
coercions: [],
|
|
397
|
+
budgetDeltas: [],
|
|
398
|
+
execute: async () => {
|
|
399
|
+
await this.client.request("DELETE", path, { orgId });
|
|
400
|
+
return [path.split("/").at(-1)];
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
}
|
|
321
404
|
};
|
|
405
|
+
function normalizeApiPath(path) {
|
|
406
|
+
const normalized = path.replace(/^\/+/, "").trim();
|
|
407
|
+
if (!normalized || normalized.includes("://") || normalized.includes("..") || normalized.includes("#")) {
|
|
408
|
+
throw new AdportError2("INVALID_INPUT", "apple: path must be a relative API path without traversal or fragments");
|
|
409
|
+
}
|
|
410
|
+
return normalized;
|
|
411
|
+
}
|
|
412
|
+
function validateMutationPath(path) {
|
|
413
|
+
const normalized = normalizeApiPath(path);
|
|
414
|
+
if (!APPLE_MUTATION_ROOTS.test(normalized) || normalized.includes("/find") || normalized.startsWith("reports/")) {
|
|
415
|
+
throw new AdportError2("INVALID_INPUT", `apple: unsupported mutation path "${normalized}"`);
|
|
416
|
+
}
|
|
417
|
+
return normalized;
|
|
418
|
+
}
|
|
419
|
+
function isRecord(value) {
|
|
420
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
421
|
+
}
|
|
422
|
+
function coerceCreatedStatuses(value, coercions, path = "body") {
|
|
423
|
+
if (Array.isArray(value)) {
|
|
424
|
+
value.forEach((item, index) => coerceCreatedStatuses(item, coercions, `${path}[${index}]`));
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
if (!isRecord(value)) return;
|
|
428
|
+
for (const [key, child] of Object.entries(value)) {
|
|
429
|
+
if ((key === "status" || key === "campaignStatus" || key === "adGroupStatus") && child === "ENABLED") {
|
|
430
|
+
value[key] = "PAUSED";
|
|
431
|
+
coercions.push(`${path}.${key} coerced to PAUSED by policy (paused_creation)`);
|
|
432
|
+
} else {
|
|
433
|
+
coerceCreatedStatuses(child, coercions, `${path}.${key}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
function isMoneyKey(key) {
|
|
438
|
+
return /(budget|bidAmount|cpaGoal)/i.test(key);
|
|
439
|
+
}
|
|
440
|
+
function containsMoneyField(value) {
|
|
441
|
+
if (Array.isArray(value)) return value.some(containsMoneyField);
|
|
442
|
+
if (!isRecord(value)) return false;
|
|
443
|
+
return Object.entries(value).some(([key, child]) => isMoneyKey(key) || containsMoneyField(child));
|
|
444
|
+
}
|
|
445
|
+
function collectCreatedMoney(value, path = "body") {
|
|
446
|
+
const deltas = [];
|
|
447
|
+
if (Array.isArray(value)) {
|
|
448
|
+
value.forEach((item, index) => deltas.push(...collectCreatedMoney(item, `${path}[${index}]`)));
|
|
449
|
+
return deltas;
|
|
450
|
+
}
|
|
451
|
+
if (!isRecord(value)) return deltas;
|
|
452
|
+
for (const [key, child] of Object.entries(value)) {
|
|
453
|
+
const childPath = `${path}.${key}`;
|
|
454
|
+
if (isMoneyKey(key)) {
|
|
455
|
+
const amount = isRecord(child) ? Number(child.amount) : Number(child);
|
|
456
|
+
if (Number.isFinite(amount) && amount >= 0) {
|
|
457
|
+
deltas.push({ target: childPath, toMicros: Math.round(amount * UNITS_TO_MICROS) });
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
deltas.push(...collectCreatedMoney(child, childPath));
|
|
461
|
+
}
|
|
462
|
+
return deltas;
|
|
463
|
+
}
|
|
464
|
+
function extractResourceIds(value, fallback) {
|
|
465
|
+
const ids = [];
|
|
466
|
+
const visit = (item) => {
|
|
467
|
+
if (Array.isArray(item)) return item.forEach(visit);
|
|
468
|
+
if (!isRecord(item)) return;
|
|
469
|
+
if (item.id !== void 0) ids.push(String(item.id));
|
|
470
|
+
for (const child of Object.values(item)) visit(child);
|
|
471
|
+
};
|
|
472
|
+
visit(value);
|
|
473
|
+
return ids.length > 0 ? [...new Set(ids)] : fallback ? [fallback.split("/").at(-1)] : [];
|
|
474
|
+
}
|
|
475
|
+
function aggregateAccountRows(rows, provider, accountId) {
|
|
476
|
+
const metrics = Object.fromEntries(
|
|
477
|
+
Object.keys(rows[0].metrics).map((metric) => [
|
|
478
|
+
metric,
|
|
479
|
+
round2(rows.reduce((sum, row) => sum + (row.metrics[metric] ?? 0), 0))
|
|
480
|
+
])
|
|
481
|
+
);
|
|
482
|
+
const spend = metrics.spend ?? 0;
|
|
483
|
+
const impressions = metrics.impressions ?? 0;
|
|
484
|
+
const clicks = metrics.clicks ?? 0;
|
|
485
|
+
const conversions = metrics.conversions ?? 0;
|
|
486
|
+
const conversionValue = metrics.conversion_value ?? 0;
|
|
487
|
+
if ("ctr" in metrics) metrics.ctr = impressions > 0 ? round2(clicks / impressions * 100) : 0;
|
|
488
|
+
if ("cpc" in metrics) metrics.cpc = clicks > 0 ? round2(spend / clicks) : 0;
|
|
489
|
+
if ("cpm" in metrics) metrics.cpm = impressions > 0 ? round2(spend / impressions * 1e3) : 0;
|
|
490
|
+
if ("cpa" in metrics) metrics.cpa = conversions > 0 ? round2(spend / conversions) : 0;
|
|
491
|
+
if ("roas" in metrics) metrics.roas = spend > 0 ? round2(conversionValue / spend) : 0;
|
|
492
|
+
return { provider, accountId, entity: { level: "account", id: accountId, name: accountId }, metrics };
|
|
493
|
+
}
|
|
322
494
|
function round2(n) {
|
|
323
495
|
return Math.round(n * 100) / 100;
|
|
324
496
|
}
|
|
@@ -329,6 +501,21 @@ import { z } from "zod";
|
|
|
329
501
|
var statusSchema = z.enum(["ENABLED", "PAUSED"]);
|
|
330
502
|
function appleTools(provider) {
|
|
331
503
|
return [
|
|
504
|
+
defineTool({
|
|
505
|
+
name: "apple_api_read",
|
|
506
|
+
namespace: "apple",
|
|
507
|
+
description: "Call any documented Apple Ads v5 read/query/report endpoint. GET supports public entity reads; POST is restricted to selector /find endpoints and report endpoints.",
|
|
508
|
+
input: z.object({
|
|
509
|
+
account_id: z.string().optional().describe("Apple Ads orgId; omit only for unscoped endpoints such as acls"),
|
|
510
|
+
method: z.enum(["GET", "POST"]).default("GET"),
|
|
511
|
+
path: z.string().min(1).describe("Relative v5 path, for example campaigns/123/adgroups or reports/campaigns/123/keywords"),
|
|
512
|
+
body: z.record(z.string(), z.unknown()).optional().describe("Selector or reporting request for POST reads")
|
|
513
|
+
}),
|
|
514
|
+
annotations: { readOnly: true },
|
|
515
|
+
async handler(input) {
|
|
516
|
+
return provider.apiRead(input);
|
|
517
|
+
}
|
|
518
|
+
}),
|
|
332
519
|
defineTool({
|
|
333
520
|
name: "apple_campaigns",
|
|
334
521
|
namespace: "apple",
|
|
@@ -373,6 +560,37 @@ function appleTools(provider) {
|
|
|
373
560
|
provider: "apple",
|
|
374
561
|
kind: "update",
|
|
375
562
|
payload: z.object({ campaign_id: z.string(), daily_budget: z.number().positive() })
|
|
563
|
+
}),
|
|
564
|
+
guardedWriteTool({
|
|
565
|
+
name: "apple_api_create",
|
|
566
|
+
namespace: "apple",
|
|
567
|
+
description: "Create a documented Apple Ads v5 entity using a relative endpoint and API-shaped body. Created ENABLED statuses are coerced to PAUSED; budget/bid Money fields are reported to policy.",
|
|
568
|
+
provider: "apple",
|
|
569
|
+
kind: "create",
|
|
570
|
+
payload: z.object({
|
|
571
|
+
path: z.string().min(1),
|
|
572
|
+
body: z.record(z.string(), z.unknown())
|
|
573
|
+
})
|
|
574
|
+
}),
|
|
575
|
+
guardedWriteTool({
|
|
576
|
+
name: "apple_api_update",
|
|
577
|
+
namespace: "apple",
|
|
578
|
+
description: "Update a documented non-monetary Apple Ads v5 entity. Budget/bid changes are rejected here and require typed tools with current-value policy checks.",
|
|
579
|
+
provider: "apple",
|
|
580
|
+
kind: "update",
|
|
581
|
+
payload: z.object({
|
|
582
|
+
path: z.string().min(1),
|
|
583
|
+
body: z.record(z.string(), z.unknown())
|
|
584
|
+
})
|
|
585
|
+
}),
|
|
586
|
+
guardedWriteTool({
|
|
587
|
+
name: "apple_api_delete",
|
|
588
|
+
namespace: "apple",
|
|
589
|
+
description: "Delete a documented Apple Ads v5 campaign-management entity by relative path.",
|
|
590
|
+
provider: "apple",
|
|
591
|
+
kind: "remove",
|
|
592
|
+
destructive: true,
|
|
593
|
+
payload: z.object({ path: z.string().min(1) })
|
|
376
594
|
})
|
|
377
595
|
];
|
|
378
596
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/jwt.ts","../src/provider.ts","../src/tools.ts","../src/index.ts"],"sourcesContent":["import { AdportError } from '@adport/core';\nimport { createClientSecret } from './jwt.js';\n\nexport interface AppleCredentials {\n clientId: string;\n teamId: string;\n keyId: string;\n /** PEM contents of the .p8 EC private key. */\n privateKeyPem: string;\n}\n\nconst TOKEN_URL = 'https://appleid.apple.com/auth/oauth2/token';\n\n/**\n * VERSION ISOLATION: everything version-specific lives in these constants and\n * the envelope helpers. The Campaign Management API v5 sunsets 2027-01-26; the\n * successor \"Apple Ads Platform API\" (v1, preview July 2026) changes, per\n * Apple's preview guide: base URL → https://api.ads.apple.com/v1, envelope\n * `data` → `result`, X-AP-Context orgId= → adAccountId=, GET-all//find →\n * POST /{entity}/query, error shape → {error:{code,message,details[]}}.\n * Migrate here when the Platform API reference goes live.\n */\nexport const APPLE_ADS_BASE = 'https://api.searchads.apple.com/api/v5';\n\nexport interface AppleEnvelope<T> {\n data: T;\n pagination?: { totalResults: number; startIndex: number; itemsPerPage: number } | null;\n error?: { errors?: Array<{ messageCode?: string; message?: string; field?: string }> } | null;\n}\n\nexport class AppleAdsClient {\n private accessToken?: { token: string; expiresAt: number };\n\n constructor(\n private readonly credentials: AppleCredentials,\n private readonly fetchImpl: typeof fetch = fetch,\n ) {}\n\n async getAccessToken(): Promise<string> {\n if (this.accessToken && this.accessToken.expiresAt > Date.now()) {\n return this.accessToken.token;\n }\n // Mint a fresh short-lived client secret per request — no 180-day rotation to manage.\n const clientSecret = createClientSecret(this.credentials);\n const response = await this.fetchImpl(TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: this.credentials.clientId,\n client_secret: clientSecret,\n scope: 'searchadsorg',\n }),\n });\n const raw = await response.text();\n if (!response.ok) {\n throw new AdportError(\n 'PROVIDER_ERROR',\n `Apple Ads OAuth failed (${response.status}). Check clientId/teamId/keyId and that the public key is uploaded in Account Settings > API.`,\n safeJson(raw),\n );\n }\n const data = JSON.parse(raw) as { access_token: string; expires_in: number };\n this.accessToken = { token: data.access_token, expiresAt: Date.now() + (data.expires_in - 60) * 1000 };\n return this.accessToken.token;\n }\n\n /** orgId (as X-AP-Context) is required on all endpoints except /acls and /me. */\n async request<T>(\n method: 'GET' | 'POST' | 'PUT',\n path: string,\n options: { orgId?: string; body?: unknown } = {},\n ): Promise<AppleEnvelope<T>> {\n const token = await this.getAccessToken();\n const response = await this.fetchImpl(`${APPLE_ADS_BASE}/${path.replace(/^\\//, '')}`, {\n method,\n headers: {\n authorization: `Bearer ${token}`,\n ...(options.orgId ? { 'X-AP-Context': `orgId=${options.orgId}` } : {}),\n ...(options.body !== undefined ? { 'content-type': 'application/json' } : {}),\n },\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n });\n const raw = await response.text();\n if (!response.ok) {\n throw new AdportError('PROVIDER_ERROR', formatAppleError(response.status, raw), safeJson(raw));\n }\n return (raw ? JSON.parse(raw) : { data: undefined }) as AppleEnvelope<T>;\n }\n}\n\nfunction safeJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/** v5 error shape: {\"error\": {\"errors\": [{\"messageCode\", \"message\", \"field\"}]}} */\nexport function formatAppleError(status: number, raw: string): string {\n const parsed = safeJson(raw) as {\n error?: { errors?: Array<{ messageCode?: string; message?: string; field?: string }> };\n };\n const items = parsed?.error?.errors ?? [];\n const head = `Apple Ads API error (HTTP ${status})`;\n if (items.length === 0) return head;\n const lines = items.map(\n (e) => `${e.messageCode ?? '?'}: ${e.message ?? ''}${e.field && e.field !== 'null' ? ` (field: ${e.field})` : ''}`,\n );\n const hint = status === 401 ? '\\n Token or org access problem — check credentials and org roles.' : '';\n return `${head}\\n ${lines.join('\\n ')}${hint}`;\n}\n","import { createPrivateKey, sign } from 'node:crypto';\n\nexport interface ClientSecretInput {\n /** SEARCHADS.<uuid> */\n clientId: string;\n /** SEARCHADS.<uuid> — equals clientId for self-managed orgs. */\n teamId: string;\n /** keyId of the public key uploaded in the Apple Ads UI. */\n keyId: string;\n /** EC prime256v1 private key, PEM (.p8 contents). */\n privateKeyPem: string;\n /** Secret lifetime in seconds; Apple caps exp at iat + 180 days. */\n lifetimeSeconds?: number;\n}\n\nfunction b64url(data: Buffer | string): string {\n return Buffer.from(data).toString('base64url');\n}\n\n/**\n * Apple Ads client secret: a self-signed ES256 JWT (header {alg, kid}; claims\n * iss=teamId, sub=clientId, aud=https://appleid.apple.com, iat, exp≤iat+180d).\n * We mint a short-lived secret per token request instead of storing one.\n */\nexport function createClientSecret(input: ClientSecretInput, now = new Date()): string {\n const iat = Math.floor(now.getTime() / 1000);\n const lifetime = Math.min(input.lifetimeSeconds ?? 3600, 180 * 86_400 - 60);\n const header = { alg: 'ES256', kid: input.keyId };\n const payload = {\n iss: input.teamId,\n iat,\n exp: iat + lifetime,\n aud: 'https://appleid.apple.com',\n sub: input.clientId,\n };\n const signingInput = `${b64url(JSON.stringify(header))}.${b64url(JSON.stringify(payload))}`;\n const key = createPrivateKey(input.privateKeyPem);\n // JWS ES256 requires the raw r||s signature form, not ASN.1/DER.\n const signature = sign('sha256', Buffer.from(signingInput), { key, dsaEncoding: 'ieee-p1363' });\n return `${signingInput}.${b64url(signature)}`;\n}\n","import {\n AdportError,\n resolveDateRange,\n type Account,\n type AdProvider,\n type MetricName,\n type NormalizedQuery,\n type ProviderCapabilities,\n type Report,\n type ReportRow,\n type StandardActions,\n type WriteGuard,\n type WriteOperation,\n type WritePreview,\n type WriteResult,\n} from '@adport/core';\nimport { AppleAdsClient } from './client.js';\n\n/** Apple Money amounts are strings in whole currency units. */\nexport const UNITS_TO_MICROS = 1_000_000;\n\ninterface Money {\n amount: string;\n currency: string;\n}\n\ninterface AppleCampaign {\n id: number;\n name: string;\n status: 'ENABLED' | 'PAUSED';\n servingStatus?: string;\n displayStatus?: string;\n dailyBudgetAmount?: Money;\n adamId?: number;\n countriesOrRegions?: string[];\n billingEvent?: string;\n supplySources?: string[];\n}\n\ninterface SpendRow {\n impressions?: number;\n taps?: number;\n ttr?: number;\n totalInstalls?: number;\n localSpend?: Money;\n tapInstallCPI?: Money;\n tapInstallRate?: number;\n}\n\ninterface ReportingRow {\n other?: boolean;\n total?: SpendRow;\n metadata?: { campaignId?: number; campaignName?: string; campaignStatus?: string };\n}\n\ninterface WritePlan {\n summary: string;\n changes: string[];\n coercions: string[];\n budgetDeltas: WritePreview['budgetDeltas'];\n execute: () => Promise<string[]>;\n}\n\nexport class AppleAdsProvider implements AdProvider {\n readonly id = 'apple';\n\n constructor(private readonly client: AppleAdsClient) {}\n\n capabilities(): ProviderCapabilities {\n // No validate-only mode in the Campaign Management API — client-side previews.\n return { serverDryRun: false };\n }\n\n standardActions(): StandardActions {\n return {\n pauseCampaign: (accountId, campaignId) => ({\n tool: 'apple_set_campaign_status',\n input: { account_id: accountId, campaign_id: campaignId, status: 'PAUSED' },\n }),\n };\n }\n\n /** Apple \"accounts\" are organizations from the user ACL. */\n async listAccounts(): Promise<Account[]> {\n const envelope = await this.client.request<\n Array<{ orgId: number; orgName: string; currency?: string; roleNames?: string[]; timeZone?: string }>\n >('GET', 'acls');\n return (envelope.data ?? []).map((acl) => ({\n provider: this.id,\n id: String(acl.orgId),\n name: acl.orgName,\n currency: acl.currency,\n status: acl.roleNames?.join(',') || undefined,\n }));\n }\n\n async listCampaigns(orgId: string, limit = 100): Promise<AppleCampaign[]> {\n const envelope = await this.client.request<AppleCampaign[]>('GET', `campaigns?limit=${limit}&offset=0`, {\n orgId,\n });\n return envelope.data ?? [];\n }\n\n async getCampaign(orgId: string, campaignId: string): Promise<AppleCampaign> {\n const envelope = await this.client.request<AppleCampaign[]>('POST', 'campaigns/find', {\n orgId,\n body: {\n conditions: [{ field: 'id', operator: 'EQUALS', values: [String(campaignId)] }],\n pagination: { offset: 0, limit: 1 },\n },\n });\n const campaign = envelope.data?.[0];\n if (!campaign) {\n throw new AdportError('PROVIDER_ERROR', `apple: campaign ${campaignId} not found in org ${orgId}`);\n }\n return campaign;\n }\n\n async report(query: NormalizedQuery): Promise<Report> {\n if (query.level !== 'campaign' && query.level !== 'account') {\n throw new AdportError('INVALID_INPUT', 'apple: report supports campaign and account levels in v0');\n }\n const range = resolveDateRange(query.dateRange);\n const accountIds = query.accountIds ?? (await this.listAccounts()).map((a) => a.id);\n const rows: ReportRow[] = [];\n for (const orgId of accountIds) {\n const envelope = await this.client.request<{ reportingDataResponse?: { row?: ReportingRow[] } }>(\n 'POST',\n 'reports/campaigns',\n {\n orgId,\n body: {\n startTime: range.start,\n endTime: range.end,\n selector: {\n orderBy: [{ field: 'campaignId', sortOrder: 'ASCENDING' }],\n pagination: { offset: 0, limit: Math.min(query.limit ?? 200, 1000) },\n },\n timeZone: 'UTC',\n returnRowTotals: true,\n returnGrandTotals: true,\n returnRecordsWithNoMetrics: false,\n },\n },\n );\n for (const row of envelope.data?.reportingDataResponse?.row ?? []) {\n rows.push(this.toReportRow(row, orgId, query));\n }\n }\n return { rows };\n }\n\n private toReportRow(row: ReportingRow, orgId: string, query: NormalizedQuery): ReportRow {\n const total = row.total ?? {};\n const spend = Number(total.localSpend?.amount ?? 0);\n const impressions = total.impressions ?? 0;\n // Apple has taps, not clicks; installs are the conversion event. No revenue metric exists.\n const clicks = total.taps ?? 0;\n const conversions = total.totalInstalls ?? 0;\n const all: Record<MetricName, number> = {\n spend: round2(spend),\n impressions,\n clicks,\n conversions,\n conversion_value: 0,\n ctr: impressions > 0 ? round2((clicks / impressions) * 100) : 0,\n cpc: clicks > 0 ? round2(spend / clicks) : 0,\n cpm: impressions > 0 ? round2((spend / impressions) * 1000) : 0,\n cpa: conversions > 0 ? round2(spend / conversions) : 0,\n roas: 0,\n };\n return {\n provider: this.id,\n accountId: orgId,\n entity: {\n level: 'campaign',\n id: String(row.metadata?.campaignId ?? ''),\n name: row.metadata?.campaignName ?? '',\n status: row.metadata?.campaignStatus,\n },\n metrics: Object.fromEntries(query.metrics.map((m) => [m, all[m]])),\n };\n }\n\n async previewWrite(op: WriteOperation, guard: WriteGuard): Promise<WritePreview> {\n const plan = await this.plan(op, guard);\n return {\n summary: plan.summary,\n changes: plan.changes,\n coercions: plan.coercions,\n budgetDeltas: plan.budgetDeltas,\n serverValidated: false,\n };\n }\n\n async applyWrite(op: WriteOperation, guard: WriteGuard): Promise<WriteResult> {\n const plan = await this.plan(op, guard);\n const resourceIds = await plan.execute();\n return { applied: true, resourceIds };\n }\n\n private async plan(op: WriteOperation, guard: WriteGuard): Promise<WritePlan> {\n const payload = op.payload as never;\n switch (op.tool) {\n case 'apple_create_campaign':\n return this.planCreateCampaign(op.accountId, payload, guard);\n case 'apple_set_campaign_status':\n return this.planSetStatus(op.accountId, payload);\n case 'apple_set_budget':\n return this.planSetBudget(op.accountId, payload);\n default:\n throw new AdportError('PROVIDER_ERROR', `apple: unsupported write tool ${op.tool}`);\n }\n }\n\n private async planCreateCampaign(\n orgId: string,\n payload: {\n name: string;\n adam_id: number;\n countries_or_regions: string[];\n daily_budget: number;\n currency: string;\n status?: string;\n },\n guard: WriteGuard,\n ): Promise<WritePlan> {\n const coercions: string[] = [];\n let status = payload.status ?? 'ENABLED';\n if (guard.forcePausedCreation && status === 'ENABLED') {\n status = 'PAUSED';\n coercions.push('status coerced to PAUSED by policy (paused_creation)');\n }\n // budgetAmount (lifetime) was removed in v5.6 — dailyBudgetAmount only.\n const body = {\n orgId: Number(orgId),\n name: payload.name,\n adamId: payload.adam_id,\n countriesOrRegions: payload.countries_or_regions,\n dailyBudgetAmount: { amount: String(payload.daily_budget), currency: payload.currency },\n adChannelType: 'SEARCH',\n billingEvent: 'TAPS',\n supplySources: ['APPSTORE_SEARCH_RESULTS'],\n status,\n };\n return {\n summary: `Create Apple Ads campaign \"${payload.name}\" (${status}) — daily budget ${payload.daily_budget} ${payload.currency}`,\n changes: [\n `+ campaign \"${payload.name}\" app=${payload.adam_id} regions=[${payload.countries_or_regions.join(', ')}] status=${status}`,\n ],\n coercions,\n budgetDeltas: [\n { target: `new campaign \"${payload.name}\" daily budget`, toMicros: payload.daily_budget * UNITS_TO_MICROS },\n ],\n execute: async () => {\n const envelope = await this.client.request<AppleCampaign>('POST', 'campaigns', { orgId, body });\n return envelope.data?.id ? [String(envelope.data.id)] : [];\n },\n };\n }\n\n private async planSetStatus(\n orgId: string,\n payload: { campaign_id: string; status: 'ENABLED' | 'PAUSED' },\n ): Promise<WritePlan> {\n const current = await this.getCampaign(orgId, payload.campaign_id);\n return {\n summary: `Set Apple campaign \"${current.name}\" status ${current.status} → ${payload.status}`,\n changes: [`~ campaign ${payload.campaign_id} status ${current.status} → ${payload.status}`],\n coercions: [],\n budgetDeltas: [],\n execute: async () => {\n await this.client.request('PUT', `campaigns/${payload.campaign_id}`, {\n orgId,\n body: { campaign: { status: payload.status } },\n });\n return [payload.campaign_id];\n },\n };\n }\n\n private async planSetBudget(\n orgId: string,\n payload: { campaign_id: string; daily_budget: number },\n ): Promise<WritePlan> {\n const current = await this.getCampaign(orgId, payload.campaign_id);\n const fromAmount = current.dailyBudgetAmount ? Number(current.dailyBudgetAmount.amount) : undefined;\n const currency = current.dailyBudgetAmount?.currency ?? 'USD';\n return {\n summary: `Change Apple campaign \"${current.name}\" daily budget ${fromAmount ?? '(unset)'} → ${payload.daily_budget} ${currency}`,\n changes: [`~ campaign ${payload.campaign_id} dailyBudgetAmount ${fromAmount ?? '(unset)'} → ${payload.daily_budget}`],\n coercions: [],\n budgetDeltas: [\n {\n target: `campaign \"${current.name}\" daily budget`,\n ...(fromAmount !== undefined ? { fromMicros: fromAmount * UNITS_TO_MICROS } : {}),\n toMicros: payload.daily_budget * UNITS_TO_MICROS,\n },\n ],\n execute: async () => {\n await this.client.request('PUT', `campaigns/${payload.campaign_id}`, {\n orgId,\n body: { campaign: { dailyBudgetAmount: { amount: String(payload.daily_budget), currency } } },\n });\n return [payload.campaign_id];\n },\n };\n }\n}\n\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n","import { defineTool, guardedWriteTool, type AnyToolDefinition } from '@adport/core';\nimport { z } from 'zod';\nimport type { AppleAdsProvider } from './provider.js';\n\nconst statusSchema = z.enum(['ENABLED', 'PAUSED']);\n\nexport function appleTools(provider: AppleAdsProvider): AnyToolDefinition[] {\n return [\n defineTool({\n name: 'apple_campaigns',\n namespace: 'apple',\n description:\n 'List Apple Ads campaigns for an organization (id, name, status, servingStatus, dailyBudgetAmount as string Money).',\n input: z.object({\n account_id: z.string().describe('Apple Ads organization id (orgId)'),\n limit: z.number().int().positive().max(1000).default(100),\n }),\n annotations: { readOnly: true },\n async handler(input) {\n const campaigns = await provider.listCampaigns(input.account_id, input.limit);\n return { campaigns };\n },\n }),\n guardedWriteTool({\n name: 'apple_create_campaign',\n namespace: 'apple',\n description:\n 'Create an Apple Ads search campaign (App Store search results, TAPS billing). ' +\n 'daily_budget is a float in whole currency units; adam_id is the App Store app id. ' +\n 'Apple has no dry run — previews are client-side diffs.',\n provider: 'apple',\n kind: 'create',\n payload: z.object({\n name: z.string().min(1),\n adam_id: z.number().int().positive().describe('App Store app id (adamId)'),\n countries_or_regions: z.array(z.string().length(2)).min(1),\n daily_budget: z.number().positive(),\n currency: z.string().length(3).describe('Org currency, e.g. USD/EUR'),\n status: statusSchema.optional(),\n }),\n }),\n guardedWriteTool({\n name: 'apple_set_campaign_status',\n namespace: 'apple',\n description: 'Enable or pause an Apple Ads campaign.',\n provider: 'apple',\n kind: 'update',\n payload: z.object({ campaign_id: z.string(), status: statusSchema }),\n }),\n guardedWriteTool({\n name: 'apple_set_budget',\n namespace: 'apple',\n description: \"Change an Apple Ads campaign's daily budget (float, whole currency units).\",\n provider: 'apple',\n kind: 'update',\n payload: z.object({ campaign_id: z.string(), daily_budget: z.number().positive() }),\n }),\n ];\n}\n","import type { CredentialStore, ProviderModule } from '@adport/core';\nimport { AppleAdsClient, type AppleCredentials } from './client.js';\nimport { AppleAdsProvider } from './provider.js';\nimport { appleTools } from './tools.js';\n\nexport { AppleAdsClient, APPLE_ADS_BASE, formatAppleError, type AppleCredentials, type AppleEnvelope } from './client.js';\nexport { createClientSecret, type ClientSecretInput } from './jwt.js';\nexport { AppleAdsProvider, UNITS_TO_MICROS } from './provider.js';\nexport { appleTools } from './tools.js';\n\nexport async function resolveAppleCredentials(store: CredentialStore): Promise<AppleCredentials | undefined> {\n const record = await store.get('apple');\n if (record?.data.client_id && record.data.team_id && record.data.key_id && record.data.private_key) {\n return {\n clientId: record.data.client_id,\n teamId: record.data.team_id,\n keyId: record.data.key_id,\n privateKeyPem: record.data.private_key,\n };\n }\n const env = process.env;\n if (env.APPLE_ADS_CLIENT_ID && env.APPLE_ADS_TEAM_ID && env.APPLE_ADS_KEY_ID && env.APPLE_ADS_PRIVATE_KEY) {\n return {\n clientId: env.APPLE_ADS_CLIENT_ID,\n teamId: env.APPLE_ADS_TEAM_ID,\n keyId: env.APPLE_ADS_KEY_ID,\n privateKeyPem: env.APPLE_ADS_PRIVATE_KEY,\n };\n }\n return undefined;\n}\n\nexport async function createAppleModule(store: CredentialStore): Promise<ProviderModule | undefined> {\n const credentials = await resolveAppleCredentials(store);\n if (!credentials) return undefined;\n const provider = new AppleAdsProvider(new AppleAdsClient(credentials));\n return { provider, tools: appleTools(provider) };\n}\n"],"mappings":"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","names":["AdportError"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/jwt.ts","../src/provider.ts","../src/tools.ts","../src/index.ts"],"sourcesContent":["import { AdportError } from '@adport/core';\nimport { createClientSecret } from './jwt.js';\n\nexport interface AppleCredentials {\n clientId: string;\n teamId: string;\n keyId: string;\n /** PEM contents of the .p8 EC private key. */\n privateKeyPem: string;\n}\n\nconst TOKEN_URL = 'https://appleid.apple.com/auth/oauth2/token';\n\n/**\n * VERSION ISOLATION: everything version-specific lives in these constants and\n * the envelope helpers. The Campaign Management API v5 sunsets 2027-01-26; the\n * successor \"Apple Ads Platform API\" (v1, preview July 2026) changes, per\n * Apple's preview guide: base URL → https://api.ads.apple.com/v1, envelope\n * `data` → `result`, X-AP-Context orgId= → adAccountId=, GET-all//find →\n * POST /{entity}/query, error shape → {error:{code,message,details[]}}.\n * Migrate here when the Platform API reference goes live.\n */\nexport const APPLE_ADS_BASE = 'https://api.searchads.apple.com/api/v5';\n\nexport interface AppleEnvelope<T> {\n data: T;\n pagination?: { totalResults: number; startIndex: number; itemsPerPage: number } | null;\n error?: { errors?: Array<{ messageCode?: string; message?: string; field?: string }> } | null;\n}\n\nexport class AppleAdsClient {\n private accessToken?: { token: string; expiresAt: number };\n\n constructor(\n private readonly credentials: AppleCredentials,\n private readonly fetchImpl: typeof fetch = fetch,\n ) {}\n\n async getAccessToken(): Promise<string> {\n if (this.accessToken && this.accessToken.expiresAt > Date.now()) {\n return this.accessToken.token;\n }\n // Mint a fresh short-lived client secret per request — no 180-day rotation to manage.\n const clientSecret = createClientSecret(this.credentials);\n const response = await this.fetchImpl(TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: this.credentials.clientId,\n client_secret: clientSecret,\n scope: 'searchadsorg',\n }),\n });\n const raw = await response.text();\n if (!response.ok) {\n throw new AdportError(\n 'PROVIDER_ERROR',\n `Apple Ads OAuth failed (${response.status}). Check clientId/teamId/keyId and that the public key is uploaded in Account Settings > API.`,\n safeJson(raw),\n );\n }\n const data = JSON.parse(raw) as { access_token: string; expires_in: number };\n this.accessToken = { token: data.access_token, expiresAt: Date.now() + (data.expires_in - 60) * 1000 };\n return this.accessToken.token;\n }\n\n /** orgId (as X-AP-Context) is required on all endpoints except /acls and /me. */\n async request<T>(\n method: 'GET' | 'POST' | 'PUT' | 'DELETE',\n path: string,\n options: { orgId?: string; body?: unknown } = {},\n ): Promise<AppleEnvelope<T>> {\n const token = await this.getAccessToken();\n const response = await this.fetchImpl(`${APPLE_ADS_BASE}/${path.replace(/^\\//, '')}`, {\n method,\n headers: {\n authorization: `Bearer ${token}`,\n ...(options.orgId ? { 'X-AP-Context': `orgId=${options.orgId}` } : {}),\n ...(options.body !== undefined ? { 'content-type': 'application/json' } : {}),\n },\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n });\n const raw = await response.text();\n if (!response.ok) {\n throw new AdportError('PROVIDER_ERROR', formatAppleError(response.status, raw), safeJson(raw));\n }\n return (raw ? JSON.parse(raw) : { data: undefined }) as AppleEnvelope<T>;\n }\n}\n\nfunction safeJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/** v5 error shape: {\"error\": {\"errors\": [{\"messageCode\", \"message\", \"field\"}]}} */\nexport function formatAppleError(status: number, raw: string): string {\n const parsed = safeJson(raw) as {\n error?: { errors?: Array<{ messageCode?: string; message?: string; field?: string }> };\n };\n const items = parsed?.error?.errors ?? [];\n const head = `Apple Ads API error (HTTP ${status})`;\n if (items.length === 0) return head;\n const lines = items.map(\n (e) => `${e.messageCode ?? '?'}: ${e.message ?? ''}${e.field && e.field !== 'null' ? ` (field: ${e.field})` : ''}`,\n );\n const hint = status === 401 ? '\\n Token or org access problem — check credentials and org roles.' : '';\n return `${head}\\n ${lines.join('\\n ')}${hint}`;\n}\n","import { createPrivateKey, sign } from 'node:crypto';\n\nexport interface ClientSecretInput {\n /** SEARCHADS.<uuid> */\n clientId: string;\n /** SEARCHADS.<uuid> — equals clientId for self-managed orgs. */\n teamId: string;\n /** keyId of the public key uploaded in the Apple Ads UI. */\n keyId: string;\n /** EC prime256v1 private key, PEM (.p8 contents). */\n privateKeyPem: string;\n /** Secret lifetime in seconds; Apple caps exp at iat + 180 days. */\n lifetimeSeconds?: number;\n}\n\nfunction b64url(data: Buffer | string): string {\n return Buffer.from(data).toString('base64url');\n}\n\n/**\n * Apple Ads client secret: a self-signed ES256 JWT (header {alg, kid}; claims\n * iss=teamId, sub=clientId, aud=https://appleid.apple.com, iat, exp≤iat+180d).\n * We mint a short-lived secret per token request instead of storing one.\n */\nexport function createClientSecret(input: ClientSecretInput, now = new Date()): string {\n const iat = Math.floor(now.getTime() / 1000);\n const lifetime = Math.min(input.lifetimeSeconds ?? 3600, 180 * 86_400 - 60);\n const header = { alg: 'ES256', kid: input.keyId };\n const payload = {\n iss: input.teamId,\n iat,\n exp: iat + lifetime,\n aud: 'https://appleid.apple.com',\n sub: input.clientId,\n };\n const signingInput = `${b64url(JSON.stringify(header))}.${b64url(JSON.stringify(payload))}`;\n const key = createPrivateKey(input.privateKeyPem);\n // JWS ES256 requires the raw r||s signature form, not ASN.1/DER.\n const signature = sign('sha256', Buffer.from(signingInput), { key, dsaEncoding: 'ieee-p1363' });\n return `${signingInput}.${b64url(signature)}`;\n}\n","import {\n AdportError,\n resolveDateRange,\n type Account,\n type AdProvider,\n type MetricName,\n type NormalizedQuery,\n type ProviderCapabilities,\n type Report,\n type ReportRow,\n type StandardActions,\n type WriteGuard,\n type WriteOperation,\n type WritePreview,\n type WriteResult,\n} from '@adport/core';\nimport { AppleAdsClient } from './client.js';\n\n/** Apple Money amounts are strings in whole currency units. */\nexport const UNITS_TO_MICROS = 1_000_000;\n\ninterface Money {\n amount: string;\n currency: string;\n}\n\ninterface AppleCampaign {\n id: number;\n name: string;\n status: 'ENABLED' | 'PAUSED';\n servingStatus?: string;\n displayStatus?: string;\n dailyBudgetAmount?: Money;\n adamId?: number;\n countriesOrRegions?: string[];\n billingEvent?: string;\n supplySources?: string[];\n}\n\ninterface SpendRow {\n impressions?: number;\n taps?: number;\n ttr?: number;\n totalInstalls?: number;\n localSpend?: Money;\n tapInstallCPI?: Money;\n tapInstallRate?: number;\n}\n\ninterface ReportingRow {\n other?: boolean;\n total?: SpendRow;\n metadata?: { campaignId?: number; campaignName?: string; campaignStatus?: string };\n}\n\ninterface WritePlan {\n summary: string;\n changes: string[];\n coercions: string[];\n budgetDeltas: WritePreview['budgetDeltas'];\n execute: () => Promise<string[]>;\n}\n\nconst APPLE_READ_ROOTS = /^(?:acls|me|apps(?:\\/.*)?|campaigns(?:\\/.*)?|adgroups(?:\\/.*)?|targetingkeywords(?:\\/.*)?|negativekeywords(?:\\/.*)?|ads(?:\\/.*)?|creatives(?:\\/.*)?|product-pages(?:\\/.*)?|search(?:\\/.*)?|geolocations(?:\\/.*)?|budgetorders(?:\\/.*)?|reports(?:\\/.*)?|customreports(?:\\/.*)?)(?:\\?.*)?$/;\nconst APPLE_MUTATION_ROOTS = /^(?:campaigns|adgroups|targetingkeywords|negativekeywords|ads|creatives|budgetorders)(?:\\/[^?#]+)*$/;\n\nexport class AppleAdsProvider implements AdProvider {\n readonly id = 'apple';\n\n constructor(private readonly client: AppleAdsClient) {}\n\n capabilities(): ProviderCapabilities {\n // No validate-only mode in the Campaign Management API — client-side previews.\n return { serverDryRun: false };\n }\n\n standardActions(): StandardActions {\n return {\n pauseCampaign: (accountId, campaignId) => ({\n tool: 'apple_set_campaign_status',\n input: { account_id: accountId, campaign_id: campaignId, status: 'PAUSED' },\n }),\n };\n }\n\n /** Apple \"accounts\" are organizations from the user ACL. */\n async listAccounts(): Promise<Account[]> {\n const envelope = await this.client.request<\n Array<{ orgId: number; orgName: string; currency?: string; roleNames?: string[]; timeZone?: string }>\n >('GET', 'acls');\n return (envelope.data ?? []).map((acl) => ({\n provider: this.id,\n id: String(acl.orgId),\n name: acl.orgName,\n currency: acl.currency,\n status: acl.roleNames?.join(',') || undefined,\n }));\n }\n\n async listCampaigns(orgId: string, limit = 100): Promise<AppleCampaign[]> {\n const envelope = await this.client.request<AppleCampaign[]>('GET', `campaigns?limit=${limit}&offset=0`, {\n orgId,\n });\n return envelope.data ?? [];\n }\n\n async getCampaign(orgId: string, campaignId: string): Promise<AppleCampaign> {\n const envelope = await this.client.request<AppleCampaign[]>('POST', 'campaigns/find', {\n orgId,\n body: {\n conditions: [{ field: 'id', operator: 'EQUALS', values: [String(campaignId)] }],\n pagination: { offset: 0, limit: 1 },\n },\n });\n const campaign = envelope.data?.[0];\n if (!campaign) {\n throw new AdportError('PROVIDER_ERROR', `apple: campaign ${campaignId} not found in org ${orgId}`);\n }\n return campaign;\n }\n\n /**\n * Safe low-level access to the documented read surface. Apple uses POST for\n * selectors and reports, so method alone cannot determine mutability.\n */\n async apiRead(input: {\n account_id?: string;\n method: 'GET' | 'POST';\n path: string;\n body?: Record<string, unknown>;\n }): Promise<unknown> {\n const path = normalizeApiPath(input.path);\n if (!APPLE_READ_ROOTS.test(path)) {\n throw new AdportError('INVALID_INPUT', `apple: unsupported read path \"${path}\"`);\n }\n if (\n input.method === 'POST' &&\n !path.includes('/find') &&\n !path.startsWith('reports/') &&\n !path.startsWith('customreports')\n ) {\n throw new AdportError(\n 'INVALID_INPUT',\n 'apple: POST is read-only here only for /find, reports/*, and customreports endpoints',\n );\n }\n const envelope = await this.client.request(input.method, path, {\n ...(input.account_id ? { orgId: input.account_id } : {}),\n ...(input.body ? { body: input.body } : {}),\n });\n return envelope;\n }\n\n async report(query: NormalizedQuery): Promise<Report> {\n if (query.level !== 'campaign' && query.level !== 'account') {\n throw new AdportError('INVALID_INPUT', 'apple: report supports campaign and account levels in v0');\n }\n const range = resolveDateRange(query.dateRange);\n const accountIds = query.accountIds ?? (await this.listAccounts()).map((a) => a.id);\n const rows: ReportRow[] = [];\n for (const orgId of accountIds) {\n const envelope = await this.client.request<{ reportingDataResponse?: { row?: ReportingRow[] } }>(\n 'POST',\n 'reports/campaigns',\n {\n orgId,\n body: {\n startTime: range.start,\n endTime: range.end,\n selector: {\n orderBy: [{ field: 'campaignId', sortOrder: 'ASCENDING' }],\n pagination: { offset: 0, limit: Math.min(query.limit ?? 200, 1000) },\n },\n timeZone: 'UTC',\n returnRowTotals: true,\n returnGrandTotals: true,\n returnRecordsWithNoMetrics: false,\n },\n },\n );\n const providerRows = (envelope.data?.reportingDataResponse?.row ?? []).map((row) =>\n this.toReportRow(row, orgId, query),\n );\n if (query.level === 'account') {\n if (providerRows.length > 0) rows.push(aggregateAccountRows(providerRows, this.id, orgId));\n } else {\n rows.push(...providerRows);\n }\n }\n return { rows };\n }\n\n private toReportRow(row: ReportingRow, orgId: string, query: NormalizedQuery): ReportRow {\n const total = row.total ?? {};\n const spend = Number(total.localSpend?.amount ?? 0);\n const impressions = total.impressions ?? 0;\n // Apple has taps, not clicks; installs are the conversion event. No revenue metric exists.\n const clicks = total.taps ?? 0;\n const conversions = total.totalInstalls ?? 0;\n const all: Record<MetricName, number> = {\n spend: round2(spend),\n impressions,\n clicks,\n conversions,\n conversion_value: 0,\n ctr: impressions > 0 ? round2((clicks / impressions) * 100) : 0,\n cpc: clicks > 0 ? round2(spend / clicks) : 0,\n cpm: impressions > 0 ? round2((spend / impressions) * 1000) : 0,\n cpa: conversions > 0 ? round2(spend / conversions) : 0,\n roas: 0,\n };\n return {\n provider: this.id,\n accountId: orgId,\n entity: {\n level: 'campaign',\n id: String(row.metadata?.campaignId ?? ''),\n name: row.metadata?.campaignName ?? '',\n status: row.metadata?.campaignStatus,\n },\n metrics: Object.fromEntries(query.metrics.map((m) => [m, all[m]])),\n };\n }\n\n async previewWrite(op: WriteOperation, guard: WriteGuard): Promise<WritePreview> {\n const plan = await this.plan(op, guard);\n return {\n summary: plan.summary,\n changes: plan.changes,\n coercions: plan.coercions,\n budgetDeltas: plan.budgetDeltas,\n serverValidated: false,\n };\n }\n\n async applyWrite(op: WriteOperation, guard: WriteGuard): Promise<WriteResult> {\n const plan = await this.plan(op, guard);\n const resourceIds = await plan.execute();\n return { applied: true, resourceIds };\n }\n\n private async plan(op: WriteOperation, guard: WriteGuard): Promise<WritePlan> {\n const payload = op.payload as never;\n switch (op.tool) {\n case 'apple_create_campaign':\n return this.planCreateCampaign(op.accountId, payload, guard);\n case 'apple_set_campaign_status':\n return this.planSetStatus(op.accountId, payload);\n case 'apple_set_budget':\n return this.planSetBudget(op.accountId, payload);\n case 'apple_api_create':\n return this.planApiCreate(op.accountId, payload, guard);\n case 'apple_api_update':\n return this.planApiUpdate(op.accountId, payload);\n case 'apple_api_delete':\n return this.planApiDelete(op.accountId, payload);\n default:\n throw new AdportError('PROVIDER_ERROR', `apple: unsupported write tool ${op.tool}`);\n }\n }\n\n private async planCreateCampaign(\n orgId: string,\n payload: {\n name: string;\n adam_id: number;\n countries_or_regions: string[];\n daily_budget: number;\n currency: string;\n status?: string;\n },\n guard: WriteGuard,\n ): Promise<WritePlan> {\n const coercions: string[] = [];\n let status = payload.status ?? 'ENABLED';\n if (guard.forcePausedCreation && status === 'ENABLED') {\n status = 'PAUSED';\n coercions.push('status coerced to PAUSED by policy (paused_creation)');\n }\n // budgetAmount (lifetime) was removed in v5.6 — dailyBudgetAmount only.\n const body = {\n orgId: Number(orgId),\n name: payload.name,\n adamId: payload.adam_id,\n countriesOrRegions: payload.countries_or_regions,\n dailyBudgetAmount: { amount: String(payload.daily_budget), currency: payload.currency },\n adChannelType: 'SEARCH',\n billingEvent: 'TAPS',\n supplySources: ['APPSTORE_SEARCH_RESULTS'],\n status,\n };\n return {\n summary: `Create Apple Ads campaign \"${payload.name}\" (${status}) — daily budget ${payload.daily_budget} ${payload.currency}`,\n changes: [\n `+ campaign \"${payload.name}\" app=${payload.adam_id} regions=[${payload.countries_or_regions.join(', ')}] status=${status}`,\n ],\n coercions,\n budgetDeltas: [\n { target: `new campaign \"${payload.name}\" daily budget`, toMicros: payload.daily_budget * UNITS_TO_MICROS },\n ],\n execute: async () => {\n const envelope = await this.client.request<AppleCampaign>('POST', 'campaigns', { orgId, body });\n return envelope.data?.id ? [String(envelope.data.id)] : [];\n },\n };\n }\n\n private async planSetStatus(\n orgId: string,\n payload: { campaign_id: string; status: 'ENABLED' | 'PAUSED' },\n ): Promise<WritePlan> {\n const current = await this.getCampaign(orgId, payload.campaign_id);\n return {\n summary: `Set Apple campaign \"${current.name}\" status ${current.status} → ${payload.status}`,\n changes: [`~ campaign ${payload.campaign_id} status ${current.status} → ${payload.status}`],\n coercions: [],\n budgetDeltas: [],\n execute: async () => {\n await this.client.request('PUT', `campaigns/${payload.campaign_id}`, {\n orgId,\n body: { campaign: { status: payload.status } },\n });\n return [payload.campaign_id];\n },\n };\n }\n\n private async planSetBudget(\n orgId: string,\n payload: { campaign_id: string; daily_budget: number },\n ): Promise<WritePlan> {\n const current = await this.getCampaign(orgId, payload.campaign_id);\n const fromAmount = current.dailyBudgetAmount ? Number(current.dailyBudgetAmount.amount) : undefined;\n const currency = current.dailyBudgetAmount?.currency ?? 'USD';\n return {\n summary: `Change Apple campaign \"${current.name}\" daily budget ${fromAmount ?? '(unset)'} → ${payload.daily_budget} ${currency}`,\n changes: [`~ campaign ${payload.campaign_id} dailyBudgetAmount ${fromAmount ?? '(unset)'} → ${payload.daily_budget}`],\n coercions: [],\n budgetDeltas: [\n {\n target: `campaign \"${current.name}\" daily budget`,\n ...(fromAmount !== undefined ? { fromMicros: fromAmount * UNITS_TO_MICROS } : {}),\n toMicros: payload.daily_budget * UNITS_TO_MICROS,\n },\n ],\n execute: async () => {\n await this.client.request('PUT', `campaigns/${payload.campaign_id}`, {\n orgId,\n body: { campaign: { dailyBudgetAmount: { amount: String(payload.daily_budget), currency } } },\n });\n return [payload.campaign_id];\n },\n };\n }\n\n private async planApiCreate(\n orgId: string,\n payload: { path: string; body: Record<string, unknown> },\n guard: WriteGuard,\n ): Promise<WritePlan> {\n const path = validateMutationPath(payload.path);\n const body = structuredClone(payload.body);\n const coercions: string[] = [];\n if (guard.forcePausedCreation) coerceCreatedStatuses(body, coercions);\n const budgetDeltas = collectCreatedMoney(body);\n return {\n summary: `Create Apple Ads resource via POST /${path}`,\n changes: [`+ POST /${path} ${JSON.stringify(body)}`],\n coercions,\n budgetDeltas,\n execute: async () => {\n const envelope = await this.client.request<unknown>('POST', path, { orgId, body });\n return extractResourceIds(envelope.data);\n },\n };\n }\n\n private async planApiUpdate(\n orgId: string,\n payload: { path: string; body: Record<string, unknown> },\n ): Promise<WritePlan> {\n const path = validateMutationPath(payload.path);\n if (containsMoneyField(payload.body)) {\n throw new AdportError(\n 'INVALID_INPUT',\n 'apple: monetary updates require a typed budget or bid tool so current and proposed values can be policy-checked',\n );\n }\n return {\n summary: `Update Apple Ads resource via PUT /${path}`,\n changes: [`~ PUT /${path} ${JSON.stringify(payload.body)}`],\n coercions: [],\n budgetDeltas: [],\n execute: async () => {\n const envelope = await this.client.request<unknown>('PUT', path, { orgId, body: payload.body });\n return extractResourceIds(envelope.data, path);\n },\n };\n }\n\n private async planApiDelete(orgId: string, payload: { path: string }): Promise<WritePlan> {\n const path = validateMutationPath(payload.path);\n return {\n summary: `Delete Apple Ads resource via DELETE /${path}`,\n changes: [`- DELETE /${path}`],\n coercions: [],\n budgetDeltas: [],\n execute: async () => {\n await this.client.request('DELETE', path, { orgId });\n return [path.split('/').at(-1)!];\n },\n };\n }\n}\n\nfunction normalizeApiPath(path: string): string {\n const normalized = path.replace(/^\\/+/, '').trim();\n if (!normalized || normalized.includes('://') || normalized.includes('..') || normalized.includes('#')) {\n throw new AdportError('INVALID_INPUT', 'apple: path must be a relative API path without traversal or fragments');\n }\n return normalized;\n}\n\nfunction validateMutationPath(path: string): string {\n const normalized = normalizeApiPath(path);\n if (!APPLE_MUTATION_ROOTS.test(normalized) || normalized.includes('/find') || normalized.startsWith('reports/')) {\n throw new AdportError('INVALID_INPUT', `apple: unsupported mutation path \"${normalized}\"`);\n }\n return normalized;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction coerceCreatedStatuses(value: unknown, coercions: string[], path = 'body'): void {\n if (Array.isArray(value)) {\n value.forEach((item, index) => coerceCreatedStatuses(item, coercions, `${path}[${index}]`));\n return;\n }\n if (!isRecord(value)) return;\n for (const [key, child] of Object.entries(value)) {\n if ((key === 'status' || key === 'campaignStatus' || key === 'adGroupStatus') && child === 'ENABLED') {\n value[key] = 'PAUSED';\n coercions.push(`${path}.${key} coerced to PAUSED by policy (paused_creation)`);\n } else {\n coerceCreatedStatuses(child, coercions, `${path}.${key}`);\n }\n }\n}\n\nfunction isMoneyKey(key: string): boolean {\n return /(budget|bidAmount|cpaGoal)/i.test(key);\n}\n\nfunction containsMoneyField(value: unknown): boolean {\n if (Array.isArray(value)) return value.some(containsMoneyField);\n if (!isRecord(value)) return false;\n return Object.entries(value).some(([key, child]) => isMoneyKey(key) || containsMoneyField(child));\n}\n\nfunction collectCreatedMoney(value: unknown, path = 'body'): WritePreview['budgetDeltas'] {\n const deltas: WritePreview['budgetDeltas'] = [];\n if (Array.isArray(value)) {\n value.forEach((item, index) => deltas.push(...collectCreatedMoney(item, `${path}[${index}]`)));\n return deltas;\n }\n if (!isRecord(value)) return deltas;\n for (const [key, child] of Object.entries(value)) {\n const childPath = `${path}.${key}`;\n if (isMoneyKey(key)) {\n const amount = isRecord(child) ? Number(child.amount) : Number(child);\n if (Number.isFinite(amount) && amount >= 0) {\n deltas.push({ target: childPath, toMicros: Math.round(amount * UNITS_TO_MICROS) });\n }\n }\n deltas.push(...collectCreatedMoney(child, childPath));\n }\n return deltas;\n}\n\nfunction extractResourceIds(value: unknown, fallback?: string): string[] {\n const ids: string[] = [];\n const visit = (item: unknown) => {\n if (Array.isArray(item)) return item.forEach(visit);\n if (!isRecord(item)) return;\n if (item.id !== undefined) ids.push(String(item.id));\n for (const child of Object.values(item)) visit(child);\n };\n visit(value);\n return ids.length > 0 ? [...new Set(ids)] : fallback ? [fallback.split('/').at(-1)!] : [];\n}\n\nfunction aggregateAccountRows(rows: ReportRow[], provider: string, accountId: string): ReportRow {\n const metrics = Object.fromEntries(\n Object.keys(rows[0]!.metrics).map((metric) => [\n metric,\n round2(rows.reduce((sum, row) => sum + (row.metrics[metric as MetricName] ?? 0), 0)),\n ]),\n ) as Partial<Record<MetricName, number>>;\n const spend = metrics.spend ?? 0;\n const impressions = metrics.impressions ?? 0;\n const clicks = metrics.clicks ?? 0;\n const conversions = metrics.conversions ?? 0;\n const conversionValue = metrics.conversion_value ?? 0;\n if ('ctr' in metrics) metrics.ctr = impressions > 0 ? round2((clicks / impressions) * 100) : 0;\n if ('cpc' in metrics) metrics.cpc = clicks > 0 ? round2(spend / clicks) : 0;\n if ('cpm' in metrics) metrics.cpm = impressions > 0 ? round2((spend / impressions) * 1000) : 0;\n if ('cpa' in metrics) metrics.cpa = conversions > 0 ? round2(spend / conversions) : 0;\n if ('roas' in metrics) metrics.roas = spend > 0 ? round2(conversionValue / spend) : 0;\n return { provider, accountId, entity: { level: 'account', id: accountId, name: accountId }, metrics };\n}\n\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n","import { defineTool, guardedWriteTool, type AnyToolDefinition } from '@adport/core';\nimport { z } from 'zod';\nimport type { AppleAdsProvider } from './provider.js';\n\nconst statusSchema = z.enum(['ENABLED', 'PAUSED']);\n\nexport function appleTools(provider: AppleAdsProvider): AnyToolDefinition[] {\n return [\n defineTool({\n name: 'apple_api_read',\n namespace: 'apple',\n description:\n 'Call any documented Apple Ads v5 read/query/report endpoint. GET supports public entity reads; POST is restricted to selector /find endpoints and report endpoints.',\n input: z.object({\n account_id: z.string().optional().describe('Apple Ads orgId; omit only for unscoped endpoints such as acls'),\n method: z.enum(['GET', 'POST']).default('GET'),\n path: z.string().min(1).describe('Relative v5 path, for example campaigns/123/adgroups or reports/campaigns/123/keywords'),\n body: z.record(z.string(), z.unknown()).optional().describe('Selector or reporting request for POST reads'),\n }),\n annotations: { readOnly: true },\n async handler(input) {\n return provider.apiRead(input);\n },\n }),\n defineTool({\n name: 'apple_campaigns',\n namespace: 'apple',\n description:\n 'List Apple Ads campaigns for an organization (id, name, status, servingStatus, dailyBudgetAmount as string Money).',\n input: z.object({\n account_id: z.string().describe('Apple Ads organization id (orgId)'),\n limit: z.number().int().positive().max(1000).default(100),\n }),\n annotations: { readOnly: true },\n async handler(input) {\n const campaigns = await provider.listCampaigns(input.account_id, input.limit);\n return { campaigns };\n },\n }),\n guardedWriteTool({\n name: 'apple_create_campaign',\n namespace: 'apple',\n description:\n 'Create an Apple Ads search campaign (App Store search results, TAPS billing). ' +\n 'daily_budget is a float in whole currency units; adam_id is the App Store app id. ' +\n 'Apple has no dry run — previews are client-side diffs.',\n provider: 'apple',\n kind: 'create',\n payload: z.object({\n name: z.string().min(1),\n adam_id: z.number().int().positive().describe('App Store app id (adamId)'),\n countries_or_regions: z.array(z.string().length(2)).min(1),\n daily_budget: z.number().positive(),\n currency: z.string().length(3).describe('Org currency, e.g. USD/EUR'),\n status: statusSchema.optional(),\n }),\n }),\n guardedWriteTool({\n name: 'apple_set_campaign_status',\n namespace: 'apple',\n description: 'Enable or pause an Apple Ads campaign.',\n provider: 'apple',\n kind: 'update',\n payload: z.object({ campaign_id: z.string(), status: statusSchema }),\n }),\n guardedWriteTool({\n name: 'apple_set_budget',\n namespace: 'apple',\n description: \"Change an Apple Ads campaign's daily budget (float, whole currency units).\",\n provider: 'apple',\n kind: 'update',\n payload: z.object({ campaign_id: z.string(), daily_budget: z.number().positive() }),\n }),\n guardedWriteTool({\n name: 'apple_api_create',\n namespace: 'apple',\n description:\n 'Create a documented Apple Ads v5 entity using a relative endpoint and API-shaped body. Created ENABLED statuses are coerced to PAUSED; budget/bid Money fields are reported to policy.',\n provider: 'apple',\n kind: 'create',\n payload: z.object({\n path: z.string().min(1),\n body: z.record(z.string(), z.unknown()),\n }),\n }),\n guardedWriteTool({\n name: 'apple_api_update',\n namespace: 'apple',\n description:\n 'Update a documented non-monetary Apple Ads v5 entity. Budget/bid changes are rejected here and require typed tools with current-value policy checks.',\n provider: 'apple',\n kind: 'update',\n payload: z.object({\n path: z.string().min(1),\n body: z.record(z.string(), z.unknown()),\n }),\n }),\n guardedWriteTool({\n name: 'apple_api_delete',\n namespace: 'apple',\n description: 'Delete a documented Apple Ads v5 campaign-management entity by relative path.',\n provider: 'apple',\n kind: 'remove',\n destructive: true,\n payload: z.object({ path: z.string().min(1) }),\n }),\n ];\n}\n","import type { CredentialStore, ProviderModule } from '@adport/core';\nimport { AppleAdsClient, type AppleCredentials } from './client.js';\nimport { AppleAdsProvider } from './provider.js';\nimport { appleTools } from './tools.js';\n\nexport { AppleAdsClient, APPLE_ADS_BASE, formatAppleError, type AppleCredentials, type AppleEnvelope } from './client.js';\nexport { createClientSecret, type ClientSecretInput } from './jwt.js';\nexport { AppleAdsProvider, UNITS_TO_MICROS } from './provider.js';\nexport { appleTools } from './tools.js';\n\nexport async function resolveAppleCredentials(store: CredentialStore): Promise<AppleCredentials | undefined> {\n const record = await store.get('apple');\n if (record?.data.client_id && record.data.team_id && record.data.key_id && record.data.private_key) {\n return {\n clientId: record.data.client_id,\n teamId: record.data.team_id,\n keyId: record.data.key_id,\n privateKeyPem: record.data.private_key,\n };\n }\n const env = process.env;\n if (env.APPLE_ADS_CLIENT_ID && env.APPLE_ADS_TEAM_ID && env.APPLE_ADS_KEY_ID && env.APPLE_ADS_PRIVATE_KEY) {\n return {\n clientId: env.APPLE_ADS_CLIENT_ID,\n teamId: env.APPLE_ADS_TEAM_ID,\n keyId: env.APPLE_ADS_KEY_ID,\n privateKeyPem: env.APPLE_ADS_PRIVATE_KEY,\n };\n }\n return undefined;\n}\n\nexport async function createAppleModule(store: CredentialStore): Promise<ProviderModule | undefined> {\n const credentials = await resolveAppleCredentials(store);\n if (!credentials) return undefined;\n const provider = new AppleAdsProvider(new AppleAdsClient(credentials));\n return { provider, tools: appleTools(provider) };\n}\n"],"mappings":"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","names":["AdportError"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adport/provider-apple",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Apple Ads (Apple Search Ads) provider for adport — Campaign Management API with ES256 OAuth",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"zod": "^4.4.3",
|
|
20
|
-
"@adport/core": "0.
|
|
20
|
+
"@adport/core": "0.4.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "^26.1.2",
|