@synterai/sdk-js 0.1.1 → 0.2.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.mjs CHANGED
@@ -98,7 +98,7 @@ function flattenArgsToFlags(args) {
98
98
 
99
99
  // src/resources/campaigns.ts
100
100
  var LIST_CAMPAIGNS_SCRIPT_BY_PLATFORM = {
101
- google: "google_ads_list_campaigns",
101
+ google: "google_ads_get_campaigns",
102
102
  meta: "meta_ads_list_campaigns",
103
103
  linkedin: "linkedin_ads_list_campaigns",
104
104
  microsoft: "microsoft_ads_list_campaigns",
@@ -149,7 +149,7 @@ var PAUSE_CAMPAIGN_ARG_MAPPING = [
149
149
  ];
150
150
  var UPDATE_BUDGET_ARG_MAPPING = [
151
151
  { field: "campaign_id", flag: "--campaign-id", type: "string", required: true },
152
- { field: "daily_budget", flag: "--budget", type: "number", required: true }
152
+ { field: "daily_budget", flag: "--daily-budget", type: "number", required: true }
153
153
  ];
154
154
  var CampaignsResource = class {
155
155
  constructor(client) {
@@ -222,13 +222,79 @@ var CampaignsResource = class {
222
222
  const args = buildArgsFromMapping(UPDATE_BUDGET_ARG_MAPPING, input);
223
223
  return this.client.runTool("update_campaign_budget", args, "google");
224
224
  }
225
+ /**
226
+ * Update campaign budget with deterministic readback verification.
227
+ *
228
+ * Executes the budget update, waits for propagation, and reads back
229
+ * campaign status from the platform to verify the update succeeded on the wire.
230
+ */
231
+ async updateBudgetAndVerify(input) {
232
+ const mutation = await this.updateBudget(input);
233
+ const maxWaitMs = input.maxWaitMs ?? 5e3;
234
+ const pollIntervalMs = input.pollIntervalMs ?? 1e3;
235
+ const startTime = Date.now();
236
+ let lastReadback;
237
+ while (Date.now() - startTime <= maxWaitMs) {
238
+ try {
239
+ const readback = await this.list({
240
+ platform: input.platform
241
+ });
242
+ lastReadback = readback;
243
+ const campaigns = readback.campaigns || readback.data || [];
244
+ const match = campaigns.find(
245
+ (c) => String(c.id || c.campaign_id) === String(input.campaign_id)
246
+ );
247
+ if (match) {
248
+ const budget = Number(match.daily_budget_usd || match.daily_budget || match.budget);
249
+ if (Math.abs(budget - input.daily_budget) < 0.01) {
250
+ return { mutation, verified: true, readback: match };
251
+ }
252
+ }
253
+ } catch {
254
+ }
255
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
256
+ }
257
+ return { mutation, verified: false, readback: lastReadback };
258
+ }
259
+ /**
260
+ * Pause a campaign with deterministic readback verification.
261
+ *
262
+ * Executes the pause command, waits for propagation, and reads back
263
+ * campaign status from the platform to verify status === 'PAUSED' on the wire.
264
+ */
265
+ async pauseAndVerify(input) {
266
+ const mutation = await this.pause(input);
267
+ const maxWaitMs = input.maxWaitMs ?? 5e3;
268
+ const pollIntervalMs = input.pollIntervalMs ?? 1e3;
269
+ const startTime = Date.now();
270
+ let lastReadback;
271
+ while (Date.now() - startTime <= maxWaitMs) {
272
+ try {
273
+ const readback = await this.list({
274
+ platform: input.platform,
275
+ status: "PAUSED"
276
+ });
277
+ lastReadback = readback;
278
+ const campaigns = readback.campaigns || readback.data || [];
279
+ const match = campaigns.find(
280
+ (c) => String(c.id || c.campaign_id) === String(input.campaign_id)
281
+ );
282
+ if (match) {
283
+ return { mutation, verified: true, readback: match };
284
+ }
285
+ } catch {
286
+ }
287
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
288
+ }
289
+ return { mutation, verified: false, readback: lastReadback };
290
+ }
225
291
  };
226
292
 
227
293
  // src/resources/analytics.ts
228
294
  var GET_PERFORMANCE_SCRIPT_BY_PLATFORM = {
229
- google: "pull_google_ads_data",
295
+ google: "pull_google_ads",
230
296
  meta: "pull_meta_ads",
231
- linkedin: "pull_linkedin_ads_data",
297
+ linkedin: "pull_linkedin_ads",
232
298
  microsoft: "pull_microsoft_ads",
233
299
  reddit: "pull_reddit_ads",
234
300
  tiktok: "pull_tiktok_ads",
@@ -260,17 +326,22 @@ var AnalyticsResource = class {
260
326
  "google",
261
327
  input.platform
262
328
  );
263
- const args = buildArgsFromMapping(GET_PERFORMANCE_ARG_MAPPING, input, platform);
329
+ const args = buildArgsFromMapping(
330
+ GET_PERFORMANCE_ARG_MAPPING,
331
+ { ...input, date_range: input.date_range ?? "LAST_7_DAYS" },
332
+ platform
333
+ );
264
334
  return this.client.runTool(scriptName, args, platform);
265
335
  }
266
336
  /** Get daily spend breakdown across all connected ad accounts. */
267
337
  async getDailySpend(input = {}) {
268
- const platform = input.platform ?? "google";
269
- const args = ["--platform", platform.toUpperCase()];
270
- if (input.days !== void 0) {
271
- args.push("--days", String(input.days));
272
- }
273
- return this.client.runTool("get_account_daily_spend", args, platform);
338
+ const { platform, scriptName } = resolvePlatformScriptName(
339
+ GET_PERFORMANCE_SCRIPT_BY_PLATFORM,
340
+ "google",
341
+ input.platform
342
+ );
343
+ const days = input.days ?? 7;
344
+ return this.client.runTool(scriptName, ["--days", String(days)], platform);
274
345
  }
275
346
  };
276
347
 
@@ -310,6 +381,21 @@ var CREATE_CONVERSION_ARG_MAPPING = [
310
381
  var DIAGNOSE_TRACKING_ARG_MAPPING = [
311
382
  { field: "url", flag: "--url", type: "string", required: true }
312
383
  ];
384
+ var GET_PIXEL_HEALTH_ARG_MAPPING = [
385
+ { field: "site_key", flag: "--site-key", type: "string" }
386
+ ];
387
+ var LIST_EVENT_DELIVERIES_ARG_MAPPING = [
388
+ { field: "site_key", flag: "--site-key", type: "string" },
389
+ { field: "status", flag: "--status", type: "string" },
390
+ { field: "platform", flag: "--platform", type: "string" },
391
+ { field: "limit", flag: "--limit", type: "number" }
392
+ ];
393
+ var GET_CLICK_ATTRIBUTION_ARG_MAPPING = [
394
+ { field: "site_key", flag: "--site-key", type: "string" },
395
+ { field: "user_id", flag: "--user-id", type: "number" },
396
+ { field: "email", flag: "--email", type: "string" },
397
+ { field: "limit", flag: "--limit", type: "number" }
398
+ ];
313
399
  var ConversionsResource = class {
314
400
  constructor(client) {
315
401
  this.client = client;
@@ -335,7 +421,19 @@ var ConversionsResource = class {
335
421
  */
336
422
  async diagnoseTracking(input) {
337
423
  const args = buildArgsFromMapping(DIAGNOSE_TRACKING_ARG_MAPPING, input);
338
- return this.client.runTool("diagnose_conversion_tracking", args);
424
+ return this.client.runTool("diagnose_tracking", args);
425
+ }
426
+ async getPixelHealth(input = {}) {
427
+ const args = buildArgsFromMapping(GET_PIXEL_HEALTH_ARG_MAPPING, input);
428
+ return this.client.runTool("get_pixel_health", args);
429
+ }
430
+ async listEventDeliveries(input = {}) {
431
+ const args = buildArgsFromMapping(LIST_EVENT_DELIVERIES_ARG_MAPPING, input);
432
+ return this.client.runTool("list_event_deliveries", args);
433
+ }
434
+ async getClickAttribution(input = {}) {
435
+ const args = buildArgsFromMapping(GET_CLICK_ATTRIBUTION_ARG_MAPPING, input);
436
+ return this.client.runTool("get_click_attribution", args);
339
437
  }
340
438
  };
341
439
 
@@ -428,7 +526,6 @@ var RedditResource = class {
428
526
 
429
527
  // src/resources/audiences.ts
430
528
  var CONSENT_WARNING = "[@synterai/sdk-js] i_have_consent was not provided. Confirm lawful basis under GDPR/CCPA and the destination platform's terms for every identifier before staging or syncing PII, then pass `i_have_consent: true`. (Soft-launch notice \u2014 mirrors the backend's own behavior; this call is not blocked.)";
431
- var ARTIFACT_ENDPOINT = "https://api.syntermedia.ai/artifacts/audience-sync-input";
432
529
  var SYNC_AUDIENCE_SCRIPT_BY_PLATFORM = {
433
530
  google: "google_ads_create_customer_match",
434
531
  meta: "meta_ads_create_audience",
@@ -460,7 +557,7 @@ var AudiencesResource = class {
460
557
  * identifiers inline when over ~500 entries.
461
558
  *
462
559
  * Bypasses the primary `tools/run` dispatcher: different host
463
- * (`https://api.syntermedia.ai`) and a different auth header
560
+ * (`https://api.synterai.com`) and a different auth header
464
561
  * (`X-Synter-Key`, not `Authorization: Bearer`) — see SPEC.md/catalog.json
465
562
  * `transport.special`.
466
563
  */
@@ -475,7 +572,7 @@ var AudiencesResource = class {
475
572
  if (input.script_name !== void 0) payload.script_name = input.script_name;
476
573
  if (input.ttl_seconds !== void 0) payload.ttl_seconds = input.ttl_seconds;
477
574
  if (input.i_have_consent !== void 0) payload.i_have_consent = input.i_have_consent;
478
- return this.client.sendAbsolute(ARTIFACT_ENDPOINT, {
575
+ return this.client.sendAbsolute(`${this.client.getArtifactBaseUrl()}/artifacts/audience-sync-input`, {
479
576
  method: "POST",
480
577
  headers: {
481
578
  "X-Synter-Key": this.client.getApiKey(),
@@ -550,6 +647,91 @@ var AudiencesResource = class {
550
647
  }
551
648
  };
552
649
 
650
+ // src/resources/shield.ts
651
+ var ShieldResource = class {
652
+ constructor(client) {
653
+ this.client = client;
654
+ }
655
+ /**
656
+ * Inspect Agent Shield velocity limits, burst thresholds, circuit breakers,
657
+ * and kill-switch status before executing ad-spend mutations.
658
+ */
659
+ async inspect(input = {}) {
660
+ const args = [];
661
+ if (input.platform) {
662
+ args.push("--platform", input.platform);
663
+ }
664
+ const result = await this.client.runTool("inspect_agent_shield", args, input.platform);
665
+ return result;
666
+ }
667
+ };
668
+
669
+ // src/resources/angstrom.ts
670
+ var AngstromResource = class {
671
+ constructor(client) {
672
+ this.client = client;
673
+ }
674
+ /**
675
+ * Verify attribution claims against Synter Ångström's deterministic confidence rubric.
676
+ */
677
+ async verify(input = {}) {
678
+ const args = [];
679
+ if (input.platform) args.push("--platform", input.platform);
680
+ if (input.claimed_conversions !== void 0) args.push("--conversions", String(input.claimed_conversions));
681
+ if (input.claimed_revenue_usd !== void 0) args.push("--revenue", String(input.claimed_revenue_usd));
682
+ if (input.touchpoint_ids && input.touchpoint_ids.length > 0) {
683
+ args.push("--touchpoints", input.touchpoint_ids.join(","));
684
+ }
685
+ const result = await this.client.runTool("verify_angstrom_claim", args, input.platform);
686
+ return result;
687
+ }
688
+ };
689
+
690
+ // src/resources/skills.ts
691
+ var SkillsResource = class {
692
+ constructor(client) {
693
+ this.client = client;
694
+ }
695
+ /**
696
+ * Load an autonomous growth runbook by ID.
697
+ */
698
+ async get(skillId) {
699
+ const result = await this.client.runTool("get_skill", ["--skill-id", skillId]);
700
+ return result;
701
+ }
702
+ /**
703
+ * List available autonomous growth runbook IDs.
704
+ */
705
+ list() {
706
+ return [
707
+ "pmax-brand-cannibalization",
708
+ "search-hygiene-shield",
709
+ "marginal-cpa-budget-rebalancer",
710
+ "meta-asc-dark-pool-auditor",
711
+ "single-truth-attribution"
712
+ ];
713
+ }
714
+ };
715
+
716
+ // src/resources/visibility.ts
717
+ var VisibilityResource = class {
718
+ constructor(client) {
719
+ this.client = client;
720
+ }
721
+ /**
722
+ * Read AI search brand visibility and AEO share of voice across ChatGPT, Claude, Perplexity, and Gemini.
723
+ */
724
+ async get(input = {}) {
725
+ const args = [];
726
+ if (input.query) args.push("--query", input.query);
727
+ if (input.competitor_domains && input.competitor_domains.length > 0) {
728
+ args.push("--competitors", input.competitor_domains.join(","));
729
+ }
730
+ const result = await this.client.runTool("get_llm_visibility", args);
731
+ return result;
732
+ }
733
+ };
734
+
553
735
  // src/toolbox/amp-tools.ts
554
736
  var AmpToolbox = class {
555
737
  constructor(client, config = {}) {
@@ -783,7 +965,8 @@ var AmpToolbox = class {
783
965
  };
784
966
 
785
967
  // src/client.ts
786
- var DEFAULT_BASE_URL = "https://syntermedia.ai";
968
+ var DEFAULT_BASE_URL = "https://synterai.com";
969
+ var DEFAULT_ARTIFACT_BASE_URL = "https://api.synterai.com";
787
970
  var DEFAULT_TIMEOUT_MS = 3e4;
788
971
  var DEFAULT_MAX_RETRIES = 3;
789
972
  var RETRY_BASE_MS = 1e3;
@@ -801,7 +984,9 @@ var Synter = class {
801
984
  throw new SynterValidationError("`apiKey` is required to construct a Synter client.", "apiKey");
802
985
  }
803
986
  this.apiKey = fullConfig.apiKey;
804
- this.baseUrl = fullConfig.baseUrl ?? DEFAULT_BASE_URL;
987
+ const env = typeof process !== "undefined" ? process.env : void 0;
988
+ this.baseUrl = fullConfig.baseUrl ?? (env?.SYNTER_API_URL || DEFAULT_BASE_URL);
989
+ this.artifactBaseUrl = fullConfig.artifactBaseUrl ?? (env?.SYNTER_ARTIFACT_API_URL || DEFAULT_ARTIFACT_BASE_URL);
805
990
  this.timeout = fullConfig.timeout ?? DEFAULT_TIMEOUT_MS;
806
991
  this.maxRetries = fullConfig.maxRetries ?? DEFAULT_MAX_RETRIES;
807
992
  this.fetchImpl = fullConfig.fetch ?? globalThis.fetch.bind(globalThis);
@@ -814,6 +999,10 @@ var Synter = class {
814
999
  this.linkedin = new LinkedInResource(this);
815
1000
  this.reddit = new RedditResource(this);
816
1001
  this.audiences = new AudiencesResource(this);
1002
+ this.shield = new ShieldResource(this);
1003
+ this.angstrom = new AngstromResource(this);
1004
+ this.skills = new SkillsResource(this);
1005
+ this.visibility = new VisibilityResource(this);
817
1006
  this.amp = new AmpToolbox(this, ampConfig);
818
1007
  }
819
1008
  // ---------------------------------------------------------------------
@@ -853,7 +1042,7 @@ var Synter = class {
853
1042
  // ---------------------------------------------------------------------
854
1043
  /** List all connected ad accounts across platforms. */
855
1044
  async listAdAccounts() {
856
- return this.runTool("google_ads_list_customers", [], "google");
1045
+ return this.runTool("google_ads_get_customers", [], "google");
857
1046
  }
858
1047
  /**
859
1048
  * Upload an image as an asset for use in ads.
@@ -892,7 +1081,11 @@ var Synter = class {
892
1081
  "Content-Type": "application/json"
893
1082
  };
894
1083
  }
895
- /** The raw API key, for the small number of tools that need a non-Bearer header (e.g. `stage_audience_artifact`). */
1084
+ /** Artifact host used by audience staging. */
1085
+ getArtifactBaseUrl() {
1086
+ return this.artifactBaseUrl;
1087
+ }
1088
+ /** The raw API key, for tools that need a non-Bearer header. */
896
1089
  getApiKey() {
897
1090
  return this.apiKey;
898
1091
  }
@@ -1380,18 +1573,23 @@ export {
1380
1573
  AmpToolbox,
1381
1574
  AnalyticsIntegrationManager,
1382
1575
  AnalyticsResource,
1576
+ AngstromResource,
1383
1577
  AudiencesResource,
1384
1578
  CampaignsResource,
1385
1579
  ConversionsResource,
1386
1580
  CreativeResource,
1581
+ DEFAULT_ARTIFACT_BASE_URL,
1387
1582
  DEFAULT_BASE_URL,
1388
1583
  KeywordsResource,
1389
1584
  LinkedInResource,
1390
1585
  MetaResource,
1391
1586
  RedditResource,
1587
+ ShieldResource,
1588
+ SkillsResource,
1392
1589
  Synter,
1393
1590
  SynterError,
1394
1591
  SynterValidationError,
1592
+ VisibilityResource,
1395
1593
  buildConversionPayload,
1396
1594
  buildTrackingURL,
1397
1595
  buildUTMParameters,
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@synterai/sdk-js",
3
- "version": "0.1.1",
4
- "description": "TypeScript SDK for the Synter advertising API — manage campaigns across Google Ads, Meta, LinkedIn, Reddit, Microsoft, TikTok, and X",
3
+ "version": "0.2.0",
4
+ "description": "Official Synter TypeScript SDK for the Synter advertising API — manage campaigns across Google Ads, Meta, LinkedIn, Reddit, Microsoft, TikTok, and X. @iflow-mcp/* copies are unofficial.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
8
  "files": [
9
- "dist"
9
+ "dist",
10
+ "CHANGELOG.md"
10
11
  ],
11
12
  "scripts": {
12
13
  "build": "tsup src/index.ts --format cjs,esm --dts",
@@ -42,15 +43,15 @@
42
43
  "analytics",
43
44
  "ppc"
44
45
  ],
45
- "author": "SynterMedia",
46
+ "author": "Synter <hello@synterai.com>",
46
47
  "license": "MIT",
47
48
  "repository": {
48
49
  "type": "git",
49
- "url": "https://github.com/jshorwitz/synter-media.git",
50
- "directory": "packages/sdk-js"
50
+ "url": "git+https://github.com/Synter-Media-AI/synter-docs.git",
51
+ "directory": "sdk/typescript"
51
52
  },
52
- "homepage": "https://syntermedia.ai",
53
- "bugs": "https://github.com/jshorwitz/synter-media/issues",
53
+ "homepage": "https://synterai.com",
54
+ "bugs": "https://github.com/Synter-Media-AI/synter-docs/issues",
54
55
  "dependencies": {},
55
56
  "devDependencies": {
56
57
  "@types/node": "^20.10.0",