@trillboards/api-client 2.2.1 → 3.2.1

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
@@ -1,5 +1,8 @@
1
- import { __require } from './chunk-EIB4SNHX.mjs';
2
- export { generatedTypes } from './chunk-EIB4SNHX.mjs';
1
+ import { __require } from './chunk-JLSS2URG.mjs';
2
+ export { generatedTypes } from './chunk-JLSS2URG.mjs';
3
+ import { createParser } from 'eventsource-parser';
4
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
5
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
3
6
  import { createHmac, timingSafeEqual } from 'crypto';
4
7
 
5
8
  // src/error.ts
@@ -72,7 +75,7 @@ var TrillboardsError = class _TrillboardsError extends Error {
72
75
  };
73
76
 
74
77
  // src/version.ts
75
- var VERSION = "1.2.0";
78
+ var VERSION = "3.2.1";
76
79
 
77
80
  // src/http.ts
78
81
  var PUBLIC_PATHS = ["/v1/errors", "/v1/changelog", "/api/discover", "/v1/health"];
@@ -121,8 +124,15 @@ var HttpClient = class {
121
124
  constructor(config) {
122
125
  this.config = config;
123
126
  }
124
- async request(method, path, options) {
125
- const url = this.buildUrl(path, options?.params);
127
+ async request(method, path2, options) {
128
+ const response = await this.requestResponse(method, path2, options);
129
+ if (response.status === 204) return void 0;
130
+ const json = await this.readJson(response);
131
+ if (!response.ok) throw TrillboardsError.fromResponse(json, response);
132
+ return json;
133
+ }
134
+ async requestResponse(method, path2, options) {
135
+ const url = this.buildUrl(path2, options?.params);
126
136
  const headers = {
127
137
  "Content-Type": "application/json",
128
138
  "X-Trillboards-Client": `typescript-sdk/${VERSION}`,
@@ -130,7 +140,7 @@ var HttpClient = class {
130
140
  ...options?.headers ?? {}
131
141
  };
132
142
  const callerSuppliedAuth = Object.keys(options?.headers ?? {}).some((h) => h.toLowerCase() === "authorization");
133
- const isPublic = PUBLIC_PATHS.some((prefix) => path.startsWith(prefix));
143
+ const isPublic = PUBLIC_PATHS.some((prefix) => path2.startsWith(prefix));
134
144
  if (!isPublic && this.config.apiKey && !callerSuppliedAuth) {
135
145
  headers["Authorization"] = `Bearer ${this.config.apiKey}`;
136
146
  }
@@ -144,13 +154,12 @@ var HttpClient = class {
144
154
  if (options?.body !== void 0 && options.body !== null) {
145
155
  fetchOptions.body = JSON.stringify(options.body);
146
156
  }
147
- const response = await fetch(url, fetchOptions);
148
- if (response.status === 204) {
149
- return void 0;
150
- }
151
- let json;
157
+ fetchOptions.signal = options?.signal;
158
+ return fetch(url, fetchOptions);
159
+ }
160
+ async readJson(response) {
152
161
  try {
153
- json = await response.json();
162
+ return await response.json();
154
163
  } catch {
155
164
  throw new TrillboardsError({
156
165
  type: "api_error",
@@ -159,13 +168,27 @@ var HttpClient = class {
159
168
  statusCode: response.status
160
169
  });
161
170
  }
162
- if (!response.ok) {
163
- throw TrillboardsError.fromResponse(json, response);
171
+ }
172
+ /** Open one authenticated live tail. The native endpoint has no replay cursor. */
173
+ async openStream(path2, options) {
174
+ const response = await this.requestResponse("GET", path2, {
175
+ ...options,
176
+ headers: { Accept: "text/event-stream", ...options?.headers }
177
+ });
178
+ if (!response.ok) throw TrillboardsError.fromResponse(await this.readJson(response), response);
179
+ if (!/^text\/event-stream(?:;|$)/i.test(response.headers.get("content-type") || "") || !response.body) {
180
+ await response.body?.cancel();
181
+ throw new TrillboardsError({
182
+ type: "api_error",
183
+ code: "invalid_response",
184
+ message: "Expected a text/event-stream response with a body.",
185
+ statusCode: response.status
186
+ });
164
187
  }
165
- return json;
188
+ return response;
166
189
  }
167
- get(path, opts) {
168
- return this.request("GET", path, { params: opts?.params });
190
+ get(path2, opts) {
191
+ return this.request("GET", path2, { params: opts?.params });
169
192
  }
170
193
  /**
171
194
  * POST / PUT / PATCH / DELETE auto-retry on 429 + 5xx + network TypeError
@@ -178,20 +201,20 @@ var HttpClient = class {
178
201
  * of POST vs DELETE is enforced server-side via Idempotency-Key headers,
179
202
  * which the caller can attach via `opts.headers`.
180
203
  */
181
- post(path, body, opts) {
182
- return retryWithBackoff(() => this.request("POST", path, { body, headers: opts?.headers }), opts?.retry);
204
+ post(path2, body, opts) {
205
+ return retryWithBackoff(() => this.request("POST", path2, { body, headers: opts?.headers }), opts?.retry);
183
206
  }
184
- put(path, body, opts) {
185
- return retryWithBackoff(() => this.request("PUT", path, { body, headers: opts?.headers }), opts?.retry);
207
+ put(path2, body, opts) {
208
+ return retryWithBackoff(() => this.request("PUT", path2, { body, headers: opts?.headers }), opts?.retry);
186
209
  }
187
- patch(path, body, opts) {
188
- return retryWithBackoff(() => this.request("PATCH", path, { body, headers: opts?.headers }), opts?.retry);
210
+ patch(path2, body, opts) {
211
+ return retryWithBackoff(() => this.request("PATCH", path2, { body, headers: opts?.headers }), opts?.retry);
189
212
  }
190
- delete(path, opts) {
191
- return retryWithBackoff(() => this.request("DELETE", path, { headers: opts?.headers }), opts?.retry);
213
+ delete(path2, opts) {
214
+ return retryWithBackoff(() => this.request("DELETE", path2, { headers: opts?.headers }), opts?.retry);
192
215
  }
193
- buildUrl(path, params) {
194
- const base = `${this.config.baseUrl}${path}`;
216
+ buildUrl(path2, params) {
217
+ const base = `${this.config.baseUrl}${path2}`;
195
218
  if (!params || Object.keys(params).length === 0) {
196
219
  return base;
197
220
  }
@@ -413,6 +436,63 @@ var AudienceClient = class {
413
436
  return this.http.get("/v1/partner/audience/stats", { params });
414
437
  }
415
438
  };
439
+ async function* readEventStream(http, path2, params, options) {
440
+ const controller = new AbortController();
441
+ const abort = () => controller.abort(options.signal?.reason);
442
+ if (options.signal?.aborted) abort();
443
+ else options.signal?.addEventListener("abort", abort, { once: true });
444
+ let reader;
445
+ try {
446
+ const response = await http.openStream(path2, { params, signal: controller.signal });
447
+ reader = response.body.getReader();
448
+ const decoder = new TextDecoder(), events = [];
449
+ let retry;
450
+ const parser = createParser({
451
+ onRetry: (value) => {
452
+ retry = value;
453
+ },
454
+ onEvent: (frame) => {
455
+ let data;
456
+ try {
457
+ data = JSON.parse(frame.data);
458
+ } catch {
459
+ throw new TrillboardsError({
460
+ type: "api_error",
461
+ code: "invalid_response",
462
+ message: "Expected JSON data in an SSE event.",
463
+ statusCode: response.status
464
+ });
465
+ }
466
+ events.push({
467
+ event: frame.event || "message",
468
+ data,
469
+ ...frame.id === void 0 ? {} : { id: frame.id },
470
+ ...retry === void 0 ? {} : { retry }
471
+ });
472
+ retry = void 0;
473
+ }
474
+ });
475
+ while (true) {
476
+ const chunk = await reader.read();
477
+ if (chunk.done) break;
478
+ parser.feed(decoder.decode(chunk.value, { stream: true }));
479
+ while (events.length) {
480
+ if (controller.signal.aborted) throw controller.signal.reason;
481
+ yield events.shift();
482
+ }
483
+ }
484
+ parser.feed(decoder.decode());
485
+ while (events.length) yield events.shift();
486
+ } finally {
487
+ options.signal?.removeEventListener("abort", abort);
488
+ controller.abort();
489
+ try {
490
+ await reader?.cancel();
491
+ } catch {
492
+ }
493
+ reader?.releaseLock();
494
+ }
495
+ }
416
496
 
417
497
  // src/resources/data.ts
418
498
  var DataClient = class {
@@ -420,13 +500,29 @@ var DataClient = class {
420
500
  this.http = http;
421
501
  }
422
502
  /** Get venue intelligence data for a screen. */
423
- async getVenueIntelligence(screenId) {
424
- return this.http.get(`/v1/partner/venue/${screenId}`);
503
+ getVenueIntelligence(screenId) {
504
+ return this.http.get("/v1/partner/venue/" + encodeURIComponent(screenId));
425
505
  }
426
506
  /** Get API usage summary. */
427
- async getUsage(params) {
507
+ getUsage(params) {
428
508
  return this.http.get("/v1/partner/usage", { params });
429
509
  }
510
+ listScreens(query = {}) {
511
+ return this.http.get("/v1/data/screens", { params: query });
512
+ }
513
+ getHistory(screenId, query = {}) {
514
+ return this.http.get("/v1/data/screens/" + encodeURIComponent(screenId) + "/history", { params: query });
515
+ }
516
+ getAudience(screenId) {
517
+ return this.http.get("/v1/data/screens/" + encodeURIComponent(screenId) + "/audience");
518
+ }
519
+ query(body) {
520
+ return this.http.post("/v1/data/query", body);
521
+ }
522
+ /** One live tail; reconnect explicitly and recover history through bounded reads. */
523
+ stream(query = {}, options = {}) {
524
+ return readEventStream(this.http, "/v1/data/stream", query, options);
525
+ }
430
526
  };
431
527
 
432
528
  // src/resources/billing.ts
@@ -434,6 +530,19 @@ var BillingClient = class {
434
530
  constructor(http) {
435
531
  this.http = http;
436
532
  }
533
+ setup(body) {
534
+ return this.http.post("/v1/partner/billing/setup", body);
535
+ }
536
+ createCreditCheckout(body, options) {
537
+ return this.http.post("/v1/partner/billing/credits/checkout", body, { headers: { "Idempotency-Key": options.idempotencyKey } });
538
+ }
539
+ purchaseCredits(body, options) {
540
+ return this.http.post("/v1/partner/billing/credits", body, { headers: { "Idempotency-Key": options.idempotencyKey } });
541
+ }
542
+ /** Read the committed shared credit ledger after Stripe payment completes. */
543
+ getUsageSummary() {
544
+ return this.http.get("/v1/partner/billing/usage-summary");
545
+ }
437
546
  /** Get current billing info (plan, credits, usage). */
438
547
  async get() {
439
548
  return this.http.get("/v1/partner/billing");
@@ -476,6 +585,135 @@ var RoutesClient = class {
476
585
  }
477
586
  };
478
587
 
588
+ // src/resources/creativeExperiments.ts
589
+ var BASE2 = "/v1/partner/creative-experiments";
590
+ var path = (id) => `${BASE2}/${encodeURIComponent(id)}`;
591
+ var CreativeExperimentsClient = class {
592
+ constructor(http) {
593
+ this.http = http;
594
+ }
595
+ create(body) {
596
+ return this.http.post(BASE2, body);
597
+ }
598
+ configureBrand(id, body) {
599
+ return this.http.post(path(id) + "/brand", body);
600
+ }
601
+ importCreative(id, body) {
602
+ return this.http.post(path(id) + "/creatives/import", body);
603
+ }
604
+ get(id) {
605
+ return this.http.get(path(id));
606
+ }
607
+ registerVariants(id, body) {
608
+ return this.http.post(path(id) + "/variants", body);
609
+ }
610
+ updatePolicy(id, body) {
611
+ return this.http.put(path(id) + "/policy", body);
612
+ }
613
+ getRewards(id, query) {
614
+ return this.http.get(path(id) + "/rewards", { params: query });
615
+ }
616
+ generate(id, body) {
617
+ return this.http.post(path(id) + "/creatives/generate", body);
618
+ }
619
+ review(id, body) {
620
+ return this.http.post(path(id) + "/creatives/review", body);
621
+ }
622
+ stop(id, body) {
623
+ return this.http.post(path(id) + "/stop", body);
624
+ }
625
+ };
626
+ var McpToolError = class extends Error {
627
+ constructor(tool, result) {
628
+ super("Native MCP tool failed: " + tool);
629
+ this.tool = tool;
630
+ this.result = result;
631
+ this.name = "McpToolError";
632
+ }
633
+ };
634
+ var MediaBuysClient = class {
635
+ constructor(config) {
636
+ this.config = config;
637
+ }
638
+ connection() {
639
+ if (!this.connecting) {
640
+ const client = new Client({ name: "trillboards-typescript", version: VERSION });
641
+ const transport = new StreamableHTTPClientTransport(new URL(this.config.baseUrl + "/mcp"), {
642
+ requestInit: { headers: {
643
+ Authorization: "Bearer " + this.config.apiKey,
644
+ "X-Trillboards-Client": "typescript-sdk/" + VERSION,
645
+ "User-Agent": "trillboards-typescript/" + VERSION,
646
+ ...this.config.version ? { "Trillboards-Version": this.config.version } : {}
647
+ } }
648
+ });
649
+ this.client = client;
650
+ this.transport = transport;
651
+ this.connecting = client.connect(transport).then(() => client).catch(async (error) => {
652
+ await client.close();
653
+ this.client = void 0;
654
+ this.transport = void 0;
655
+ this.connecting = void 0;
656
+ throw error;
657
+ });
658
+ }
659
+ return this.connecting;
660
+ }
661
+ async call(name, args) {
662
+ const client = await this.connection();
663
+ const result = await client.callTool({ name, arguments: args });
664
+ if (result.isError) throw new McpToolError(name, result);
665
+ if (result.structuredContent) return result.structuredContent;
666
+ for (const block of result.content) {
667
+ if (block.type !== "text") continue;
668
+ try {
669
+ return JSON.parse(block.text);
670
+ } catch {
671
+ }
672
+ }
673
+ throw new McpToolError(name, result);
674
+ }
675
+ getProducts(args = {}) {
676
+ return this.call("get_products", args);
677
+ }
678
+ listAccounts(args = {}) {
679
+ return this.call("list_accounts", args);
680
+ }
681
+ syncAccounts(args) {
682
+ return this.call("sync_accounts", args);
683
+ }
684
+ create(args) {
685
+ return this.call("create_media_buy", args);
686
+ }
687
+ list(args = {}) {
688
+ return this.call("get_media_buys", args);
689
+ }
690
+ update(args) {
691
+ return this.call("update_media_buy", args);
692
+ }
693
+ getDelivery(args) {
694
+ return this.call("get_media_buy_delivery", args);
695
+ }
696
+ syncCreatives(args) {
697
+ return this.call("sync_creatives", args);
698
+ }
699
+ discoverInventory(args = {}) {
700
+ return this.call("discover_inventory", args);
701
+ }
702
+ /** Release MCP streams and terminate an optional server session. */
703
+ async close() {
704
+ await this.connecting?.catch(() => void 0);
705
+ const client = this.client, transport = this.transport;
706
+ this.client = void 0;
707
+ this.transport = void 0;
708
+ this.connecting = void 0;
709
+ try {
710
+ if (transport?.sessionId) await transport.terminateSession();
711
+ } finally {
712
+ await client?.close();
713
+ }
714
+ }
715
+ };
716
+
479
717
  // src/client.ts
480
718
  var DEFAULT_BASE_URL = "https://api.trillboards.com";
481
719
  var TrillboardsClient = class {
@@ -503,6 +741,8 @@ var TrillboardsClient = class {
503
741
  this.errors = new ErrorsClient(this._http);
504
742
  this.billing = new BillingClient(this._http);
505
743
  this.routes = new RoutesClient(this._http);
744
+ this.creativeExperiments = new CreativeExperimentsClient(this._http);
745
+ this.mediaBuys = new MediaBuysClient({ apiKey: options.apiKey, baseUrl, version: options.version });
506
746
  }
507
747
  };
508
748
  var DEFAULT_TOLERANCE_SECONDS = 300;
@@ -798,6 +1038,6 @@ var Webhooks = {
798
1038
  verifyAdcpWebhook
799
1039
  };
800
1040
 
801
- export { ADCP_WEBHOOK_SIGNING_TAG, AnalyticsClient, AudienceClient, BillingClient, DataClient, DevicesClient, EarningsClient, ErrorsClient, FleetClient, ImpressionsClient, RoutesClient, ScreensClient, TrillboardsClient, TrillboardsError, VERSION, Webhooks, WebhooksClient, constructEvent, constructEventLegacy, parseSignatureHeader, retryWithBackoff, verifyAdcpWebhook };
1041
+ export { ADCP_WEBHOOK_SIGNING_TAG, AnalyticsClient, AudienceClient, BillingClient, CreativeExperimentsClient, DataClient, DevicesClient, EarningsClient, ErrorsClient, FleetClient, ImpressionsClient, McpToolError, MediaBuysClient, RoutesClient, ScreensClient, TrillboardsClient, TrillboardsError, VERSION, Webhooks, WebhooksClient, constructEvent, constructEventLegacy, parseSignatureHeader, retryWithBackoff, verifyAdcpWebhook };
802
1042
  //# sourceMappingURL=index.mjs.map
803
1043
  //# sourceMappingURL=index.mjs.map