@trillboards/ads-sdk 2.0.0 → 2.1.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/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  All notable changes to `@trillboards/ads-sdk` will be documented in this file.
4
4
 
5
+ ## [2.1.0] - 2026-02-15
6
+
7
+ ### Features
8
+ - **CLI setup wizard**: `npx @trillboards/ads-sdk init` — registers account, creates first device, saves API key to `.env` in 30 seconds
9
+ - **Structured errors**: `TrillboardsError`, `TrillboardsAuthenticationError`, `TrillboardsRateLimitError`, `TrillboardsNotFoundError`, `TrillboardsValidationError` — all errors include `code`, `statusCode`, `type`, and `help` fields
10
+ - **Debug mode**: Set `debug: true` in config or `TRILLBOARDS_DEBUG=true` env var to log all API requests with timing
11
+ - **Environment variable auto-detection**: `PartnerClient` reads `TRILLBOARDS_API_KEY` from env — no need to pass in code
12
+ - **`PartnerClient.quickStart()`**: Static method for one-call registration + device creation + pre-authenticated client
13
+ - **Test mode detection**: `client.isTestMode` returns `true` when using a test API key (`trb_test_*`)
14
+
15
+ ### Improvements
16
+ - Error messages now include actionable help text and links to docs
17
+ - All API errors parsed from JSON response body with `type`, `code`, `message`, `param` fields
18
+ - Debug logger prefixed with `[Trillboards]` for easy filtering
19
+
5
20
  ## [2.0.0] - 2026-02-14
6
21
 
7
22
  ### Breaking Changes
package/README.md CHANGED
@@ -14,6 +14,24 @@ npm install @trillboards/ads-sdk
14
14
 
15
15
  ## Quick Start
16
16
 
17
+ ### Fastest: One-command setup
18
+
19
+ ```bash
20
+ npx @trillboards/ads-sdk init
21
+ ```
22
+
23
+ This registers your account, creates your first device, and saves your API key to `.env`. Zero configuration.
24
+
25
+ ### Server (Node.js with env var)
26
+
27
+ ```typescript
28
+ import { PartnerClient } from '@trillboards/ads-sdk/server';
29
+
30
+ // Reads TRILLBOARDS_API_KEY from environment automatically
31
+ const client = new PartnerClient();
32
+ const audience = await client.audience.getLive('screen-id');
33
+ ```
34
+
17
35
  ### Browser (core)
18
36
 
19
37
  ```typescript
@@ -75,6 +93,53 @@ The `TrillboardsConfig` interface accepts the following options:
75
93
  | `refreshInterval` | `number` | `120000` | Ad refresh interval (ms) |
76
94
  | `cacheSize` | `number` | `10` | Max cached ads |
77
95
 
96
+ ## Debug Mode
97
+
98
+ Enable debug logging to see all API requests, state transitions, and cache operations:
99
+
100
+ ```typescript
101
+ // Browser
102
+ const sdk = await TrillboardsAds.create({ deviceId: 'xxx', debug: true });
103
+
104
+ // Server
105
+ const client = new PartnerClient({ debug: true });
106
+ ```
107
+
108
+ Or set the environment variable:
109
+
110
+ ```bash
111
+ TRILLBOARDS_DEBUG=true
112
+ ```
113
+
114
+ ## Environment Variables
115
+
116
+ | Variable | Description |
117
+ |----------|-------------|
118
+ | `TRILLBOARDS_API_KEY` | API key for `PartnerClient` (avoids passing in code) |
119
+ | `TRILLBOARDS_DEBUG` | Set to `true` to enable debug logging |
120
+
121
+ ## Error Handling
122
+
123
+ The SDK throws typed errors that match the API error format:
124
+
125
+ ```typescript
126
+ import {
127
+ TrillboardsAuthenticationError,
128
+ TrillboardsRateLimitError,
129
+ } from '@trillboards/ads-sdk/server';
130
+
131
+ try {
132
+ const audience = await client.audience.getLive('screen-id');
133
+ } catch (error) {
134
+ if (error instanceof TrillboardsAuthenticationError) {
135
+ console.log('Bad API key:', error.message);
136
+ console.log('Help:', error.help);
137
+ } else if (error instanceof TrillboardsRateLimitError) {
138
+ console.log(`Rate limited. Retry after ${error.retryAfter}s`);
139
+ }
140
+ }
141
+ ```
142
+
78
143
  ## Events
79
144
 
80
145
  The SDK emits typed events via the `EventMap` interface. Subscribe with `sdk.on(event, listener)` or `sdk.once(event, listener)`.
package/dist/cli.js ADDED
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var readline = require('readline');
5
+ var fs = require('fs');
6
+ var path = require('path');
7
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
27
+ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
28
+ var path__namespace = /*#__PURE__*/_interopNamespace(path);
29
+
30
+ // src/core/config.ts
31
+ var SDK_VERSION = "2.1.0";
32
+
33
+ // src/cli.ts
34
+ var BANNER = `
35
+ _____ ___ ___ _ _ ___ ___ _ ___ ___ ___
36
+ |_ _| _ \\_ _| | | | | _ )/ _ \\ /_\\ | _ \\ \\/ __|
37
+ | | | /| || |__| |__| _ \\ (_) / _ \\| / |) \\__ \\
38
+ |_| |_|_\\___|____|____|___/\\___/_/ \\_\\_|_\\___/|___/
39
+
40
+ Turn any screen into ad revenue in 30 seconds
41
+ `;
42
+ var API_BASE = "https://api.trillboards.com/v1";
43
+ function prompt(rl, question) {
44
+ return new Promise((resolve2) => {
45
+ rl.question(question, (answer) => resolve2(answer.trim()));
46
+ });
47
+ }
48
+ async function callQuickStart(companyName, email) {
49
+ const response = await fetch(`${API_BASE}/partner/quick-start`, {
50
+ method: "POST",
51
+ headers: { "Content-Type": "application/json" },
52
+ body: JSON.stringify({
53
+ company_name: companyName,
54
+ email
55
+ }),
56
+ signal: AbortSignal.timeout(3e4)
57
+ });
58
+ const json = await response.json();
59
+ if (!response.ok) {
60
+ const msg = json?.error?.message ?? json?.message ?? `HTTP ${response.status}`;
61
+ throw new Error(msg);
62
+ }
63
+ return json.data;
64
+ }
65
+ function appendToEnvFile(apiKey) {
66
+ const envPath = path__namespace.resolve(process.cwd(), ".env");
67
+ const line = `TRILLBOARDS_API_KEY=${apiKey}
68
+ `;
69
+ if (fs__namespace.existsSync(envPath)) {
70
+ const content = fs__namespace.readFileSync(envPath, "utf-8");
71
+ if (content.includes("TRILLBOARDS_API_KEY=")) {
72
+ const updated = content.replace(/^TRILLBOARDS_API_KEY=.*$/m, `TRILLBOARDS_API_KEY=${apiKey}`);
73
+ fs__namespace.writeFileSync(envPath, updated);
74
+ } else {
75
+ const separator = content.endsWith("\n") ? "" : "\n";
76
+ fs__namespace.appendFileSync(envPath, `${separator}${line}`);
77
+ }
78
+ } else {
79
+ fs__namespace.writeFileSync(envPath, line);
80
+ }
81
+ }
82
+ async function runInit() {
83
+ console.log(BANNER);
84
+ let completed = false;
85
+ const rl = readline__namespace.createInterface({
86
+ input: process.stdin,
87
+ output: process.stdout
88
+ });
89
+ rl.on("close", () => {
90
+ if (!completed) {
91
+ console.log("\nAborted.");
92
+ process.exit(0);
93
+ }
94
+ });
95
+ try {
96
+ const companyName = await prompt(rl, " Company name: ");
97
+ if (!companyName) {
98
+ console.error("\n Error: Company name is required.");
99
+ process.exit(1);
100
+ }
101
+ const email = await prompt(rl, " Email: ");
102
+ if (!email || !email.includes("@")) {
103
+ console.error("\n Error: A valid email is required.");
104
+ process.exit(1);
105
+ }
106
+ console.log("\n Registering...\n");
107
+ const data = await callQuickStart(companyName, email);
108
+ appendToEnvFile(data.credentials.api_key);
109
+ const keyPreview = data.credentials.api_key_prefix;
110
+ const fingerprint = data.device.fingerprint;
111
+ const embedUrl = data.device.embed_url;
112
+ console.log(` Your API Key: ${keyPreview}`);
113
+ console.log(` Device ID: ${fingerprint}`);
114
+ console.log(` Embed URL: ${embedUrl}`);
115
+ console.log("");
116
+ console.log(" API key saved to .env");
117
+ console.log("");
118
+ console.log(" Quick integration:");
119
+ console.log("");
120
+ console.log(" // Node.js / server");
121
+ console.log(" import { PartnerClient } from '@trillboards/ads-sdk/server';");
122
+ console.log(" const client = new PartnerClient(); // reads from TRILLBOARDS_API_KEY");
123
+ console.log("");
124
+ console.log(" // Browser \u2014 paste in your HTML");
125
+ console.log(` <iframe src="${embedUrl}" style="width:100%;height:100%;border:none;" allow="autoplay; fullscreen" allowfullscreen></iframe>`);
126
+ console.log("");
127
+ console.log(" Next steps:");
128
+ console.log(" 1. Register more devices: POST /v1/partner/device");
129
+ console.log(" 2. Connect Stripe for payouts: POST /v1/partner/stripe/connect");
130
+ console.log(" 3. Read the docs: https://trillboards.com/developers");
131
+ console.log("");
132
+ completed = true;
133
+ } catch (err) {
134
+ console.error(`
135
+ Error: ${err.message}
136
+ `);
137
+ process.exit(1);
138
+ } finally {
139
+ rl.close();
140
+ }
141
+ }
142
+ var args = process.argv.slice(2);
143
+ if (args.includes("--version") || args.includes("-v")) {
144
+ console.log(SDK_VERSION);
145
+ process.exit(0);
146
+ }
147
+ if (args.includes("--help") || args.includes("-h")) {
148
+ console.log(`
149
+ @trillboards/ads-sdk v${SDK_VERSION}
150
+
151
+ Usage:
152
+ npx @trillboards/ads-sdk init Register and set up your first device
153
+ npx @trillboards/ads-sdk --version
154
+ npx @trillboards/ads-sdk --help
155
+ `);
156
+ process.exit(0);
157
+ }
158
+ runInit();
package/dist/index.d.mts CHANGED
@@ -13,6 +13,7 @@ interface TrillboardsConfig {
13
13
  programmaticRetry?: number;
14
14
  programmaticBackoffMax?: number;
15
15
  cacheSize?: number;
16
+ debug?: boolean;
16
17
  }
17
18
  type WaterfallMode = 'programmatic_only' | 'programmatic_then_direct' | 'direct_only';
18
19
  interface AdItem {
@@ -316,7 +317,7 @@ declare class EventEmitter {
316
317
  }
317
318
 
318
319
  /** Single source of truth for the SDK version string. */
319
- declare const SDK_VERSION = "2.0.0";
320
+ declare const SDK_VERSION = "2.1.0";
320
321
  /**
321
322
  * Compile-time constants that mirror the original IIFE CONFIG
322
323
  * object. Every value here acts as a sensible production default
@@ -335,7 +336,7 @@ declare const DEFAULT_CONFIG: {
335
336
  readonly PROGRAMMATIC_MIN_INTERVAL_MS: 5000;
336
337
  readonly PROGRAMMATIC_RETRY_MS: 5000;
337
338
  readonly PROGRAMMATIC_BACKOFF_MAX_MS: number;
338
- readonly VERSION: "2.0.0";
339
+ readonly VERSION: "2.1.0";
339
340
  };
340
341
  /**
341
342
  * Merge a caller-supplied TrillboardsConfig with the defaults,
@@ -360,6 +361,7 @@ declare function resolveConfig(userConfig: TrillboardsConfig): {
360
361
  readonly programmaticRetry: number;
361
362
  readonly programmaticBackoffMax: number;
362
363
  readonly cacheSize: number;
364
+ readonly debug: boolean;
363
365
  };
364
366
 
365
367
  /**
@@ -599,4 +601,55 @@ declare class ApiClient {
599
601
  }): Promise<boolean>;
600
602
  }
601
603
 
602
- export { type AdItem, ApiClient, type AuctionWinner, type BridgeConfig, type BridgePayload, type BridgeType, CircuitBreaker, type CircuitBreakerState, DEFAULT_CONFIG, DEFAULT_PUBLIC_STATE, EventEmitter, type EventMap, type FetchAdsResult, type ImpressionData, type PlayerTruth, type ProgrammaticSettings, SDK_VERSION, type ScreenDimensions, Telemetry, type TelemetrySnapshot, TrillboardsAds, type TrillboardsConfig, type TrillboardsState, type VastSource, WaterfallEngine, type WaterfallMode, createInitialState, getPublicState, resolveConfig };
604
+ /**
605
+ * Base error class for all Trillboards SDK errors.
606
+ * Mirrors the API error response shape: `{ type, code, message, param, help }`.
607
+ */
608
+ declare class TrillboardsError extends Error {
609
+ readonly type: string;
610
+ readonly code: string;
611
+ readonly statusCode: number;
612
+ readonly help?: string;
613
+ readonly param?: string;
614
+ constructor(message: string, options?: {
615
+ type?: string;
616
+ code?: string;
617
+ statusCode?: number;
618
+ help?: string;
619
+ param?: string;
620
+ });
621
+ }
622
+ /** Thrown on HTTP 401 — invalid or missing API key. */
623
+ declare class TrillboardsAuthenticationError extends TrillboardsError {
624
+ constructor(message?: string);
625
+ }
626
+ /** Thrown on HTTP 429 — rate limit exceeded. */
627
+ declare class TrillboardsRateLimitError extends TrillboardsError {
628
+ readonly retryAfter: number;
629
+ constructor(retryAfter: number, message?: string);
630
+ }
631
+ /** Thrown on HTTP 404 — resource not found. */
632
+ declare class TrillboardsNotFoundError extends TrillboardsError {
633
+ constructor(message?: string);
634
+ }
635
+ /** Thrown on HTTP 400 — validation / bad request. */
636
+ declare class TrillboardsValidationError extends TrillboardsError {
637
+ constructor(message?: string, param?: string);
638
+ }
639
+
640
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
641
+ declare class Logger {
642
+ private level;
643
+ setLevel(level: LogLevel): void;
644
+ getLevel(): LogLevel;
645
+ debug(message: string, data?: unknown): void;
646
+ info(message: string, data?: unknown): void;
647
+ warn(message: string, data?: unknown): void;
648
+ error(message: string, data?: unknown): void;
649
+ }
650
+ /** Singleton logger instance shared across the SDK. */
651
+ declare const logger: Logger;
652
+ /** Set the global log level for the SDK. */
653
+ declare function setLogLevel(level: LogLevel): void;
654
+
655
+ export { type AdItem, ApiClient, type AuctionWinner, type BridgeConfig, type BridgePayload, type BridgeType, CircuitBreaker, type CircuitBreakerState, DEFAULT_CONFIG, DEFAULT_PUBLIC_STATE, EventEmitter, type EventMap, type FetchAdsResult, type ImpressionData, type LogLevel, type PlayerTruth, type ProgrammaticSettings, SDK_VERSION, type ScreenDimensions, Telemetry, type TelemetrySnapshot, TrillboardsAds, TrillboardsAuthenticationError, type TrillboardsConfig, TrillboardsError, TrillboardsNotFoundError, TrillboardsRateLimitError, type TrillboardsState, TrillboardsValidationError, type VastSource, WaterfallEngine, type WaterfallMode, createInitialState, getPublicState, logger, resolveConfig, setLogLevel };
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ interface TrillboardsConfig {
13
13
  programmaticRetry?: number;
14
14
  programmaticBackoffMax?: number;
15
15
  cacheSize?: number;
16
+ debug?: boolean;
16
17
  }
17
18
  type WaterfallMode = 'programmatic_only' | 'programmatic_then_direct' | 'direct_only';
18
19
  interface AdItem {
@@ -316,7 +317,7 @@ declare class EventEmitter {
316
317
  }
317
318
 
318
319
  /** Single source of truth for the SDK version string. */
319
- declare const SDK_VERSION = "2.0.0";
320
+ declare const SDK_VERSION = "2.1.0";
320
321
  /**
321
322
  * Compile-time constants that mirror the original IIFE CONFIG
322
323
  * object. Every value here acts as a sensible production default
@@ -335,7 +336,7 @@ declare const DEFAULT_CONFIG: {
335
336
  readonly PROGRAMMATIC_MIN_INTERVAL_MS: 5000;
336
337
  readonly PROGRAMMATIC_RETRY_MS: 5000;
337
338
  readonly PROGRAMMATIC_BACKOFF_MAX_MS: number;
338
- readonly VERSION: "2.0.0";
339
+ readonly VERSION: "2.1.0";
339
340
  };
340
341
  /**
341
342
  * Merge a caller-supplied TrillboardsConfig with the defaults,
@@ -360,6 +361,7 @@ declare function resolveConfig(userConfig: TrillboardsConfig): {
360
361
  readonly programmaticRetry: number;
361
362
  readonly programmaticBackoffMax: number;
362
363
  readonly cacheSize: number;
364
+ readonly debug: boolean;
363
365
  };
364
366
 
365
367
  /**
@@ -599,4 +601,55 @@ declare class ApiClient {
599
601
  }): Promise<boolean>;
600
602
  }
601
603
 
602
- export { type AdItem, ApiClient, type AuctionWinner, type BridgeConfig, type BridgePayload, type BridgeType, CircuitBreaker, type CircuitBreakerState, DEFAULT_CONFIG, DEFAULT_PUBLIC_STATE, EventEmitter, type EventMap, type FetchAdsResult, type ImpressionData, type PlayerTruth, type ProgrammaticSettings, SDK_VERSION, type ScreenDimensions, Telemetry, type TelemetrySnapshot, TrillboardsAds, type TrillboardsConfig, type TrillboardsState, type VastSource, WaterfallEngine, type WaterfallMode, createInitialState, getPublicState, resolveConfig };
604
+ /**
605
+ * Base error class for all Trillboards SDK errors.
606
+ * Mirrors the API error response shape: `{ type, code, message, param, help }`.
607
+ */
608
+ declare class TrillboardsError extends Error {
609
+ readonly type: string;
610
+ readonly code: string;
611
+ readonly statusCode: number;
612
+ readonly help?: string;
613
+ readonly param?: string;
614
+ constructor(message: string, options?: {
615
+ type?: string;
616
+ code?: string;
617
+ statusCode?: number;
618
+ help?: string;
619
+ param?: string;
620
+ });
621
+ }
622
+ /** Thrown on HTTP 401 — invalid or missing API key. */
623
+ declare class TrillboardsAuthenticationError extends TrillboardsError {
624
+ constructor(message?: string);
625
+ }
626
+ /** Thrown on HTTP 429 — rate limit exceeded. */
627
+ declare class TrillboardsRateLimitError extends TrillboardsError {
628
+ readonly retryAfter: number;
629
+ constructor(retryAfter: number, message?: string);
630
+ }
631
+ /** Thrown on HTTP 404 — resource not found. */
632
+ declare class TrillboardsNotFoundError extends TrillboardsError {
633
+ constructor(message?: string);
634
+ }
635
+ /** Thrown on HTTP 400 — validation / bad request. */
636
+ declare class TrillboardsValidationError extends TrillboardsError {
637
+ constructor(message?: string, param?: string);
638
+ }
639
+
640
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
641
+ declare class Logger {
642
+ private level;
643
+ setLevel(level: LogLevel): void;
644
+ getLevel(): LogLevel;
645
+ debug(message: string, data?: unknown): void;
646
+ info(message: string, data?: unknown): void;
647
+ warn(message: string, data?: unknown): void;
648
+ error(message: string, data?: unknown): void;
649
+ }
650
+ /** Singleton logger instance shared across the SDK. */
651
+ declare const logger: Logger;
652
+ /** Set the global log level for the SDK. */
653
+ declare function setLogLevel(level: LogLevel): void;
654
+
655
+ export { type AdItem, ApiClient, type AuctionWinner, type BridgeConfig, type BridgePayload, type BridgeType, CircuitBreaker, type CircuitBreakerState, DEFAULT_CONFIG, DEFAULT_PUBLIC_STATE, EventEmitter, type EventMap, type FetchAdsResult, type ImpressionData, type LogLevel, type PlayerTruth, type ProgrammaticSettings, SDK_VERSION, type ScreenDimensions, Telemetry, type TelemetrySnapshot, TrillboardsAds, TrillboardsAuthenticationError, type TrillboardsConfig, TrillboardsError, TrillboardsNotFoundError, TrillboardsRateLimitError, type TrillboardsState, TrillboardsValidationError, type VastSource, WaterfallEngine, type WaterfallMode, createInitialState, getPublicState, logger, resolveConfig, setLogLevel };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // src/core/config.ts
4
- var SDK_VERSION = "2.0.0";
4
+ var SDK_VERSION = "2.1.0";
5
5
  var DEFAULT_CONFIG = {
6
6
  API_BASE: "https://api.trillboards.com/v1/partner",
7
7
  CDN_BASE: "https://cdn.trillboards.com",
@@ -44,7 +44,8 @@ function resolveConfig(userConfig) {
44
44
  programmaticMinInterval: Math.max(userConfig.programmaticMinInterval ?? DEFAULT_CONFIG.PROGRAMMATIC_MIN_INTERVAL_MS, 1e3),
45
45
  programmaticRetry: Math.max(userConfig.programmaticRetry ?? DEFAULT_CONFIG.PROGRAMMATIC_RETRY_MS, 1e3),
46
46
  programmaticBackoffMax: Math.max(userConfig.programmaticBackoffMax ?? DEFAULT_CONFIG.PROGRAMMATIC_BACKOFF_MAX_MS, 5e3),
47
- cacheSize: Math.max(userConfig.cacheSize ?? DEFAULT_CONFIG.CACHE_SIZE, 1)
47
+ cacheSize: Math.max(userConfig.cacheSize ?? DEFAULT_CONFIG.CACHE_SIZE, 1),
48
+ debug: userConfig.debug ?? false
48
49
  };
49
50
  }
50
51
 
@@ -171,6 +172,67 @@ var EventEmitter = class {
171
172
  }
172
173
  };
173
174
 
175
+ // src/logger.ts
176
+ var LEVEL_PRIORITY = {
177
+ debug: 0,
178
+ info: 1,
179
+ warn: 2,
180
+ error: 3,
181
+ none: 4
182
+ };
183
+ var PREFIX = "[Trillboards]";
184
+ var Logger = class {
185
+ constructor() {
186
+ this.level = "none";
187
+ }
188
+ setLevel(level) {
189
+ this.level = level;
190
+ }
191
+ getLevel() {
192
+ return this.level;
193
+ }
194
+ debug(message, data) {
195
+ if (LEVEL_PRIORITY[this.level] <= LEVEL_PRIORITY.debug) {
196
+ if (data !== void 0) {
197
+ console.debug(PREFIX, message, data);
198
+ } else {
199
+ console.debug(PREFIX, message);
200
+ }
201
+ }
202
+ }
203
+ info(message, data) {
204
+ if (LEVEL_PRIORITY[this.level] <= LEVEL_PRIORITY.info) {
205
+ if (data !== void 0) {
206
+ console.info(PREFIX, message, data);
207
+ } else {
208
+ console.info(PREFIX, message);
209
+ }
210
+ }
211
+ }
212
+ warn(message, data) {
213
+ if (LEVEL_PRIORITY[this.level] <= LEVEL_PRIORITY.warn) {
214
+ if (data !== void 0) {
215
+ console.warn(PREFIX, message, data);
216
+ } else {
217
+ console.warn(PREFIX, message);
218
+ }
219
+ }
220
+ }
221
+ error(message, data) {
222
+ if (LEVEL_PRIORITY[this.level] <= LEVEL_PRIORITY.error) {
223
+ if (data !== void 0) {
224
+ console.error(PREFIX, message, data);
225
+ } else {
226
+ console.error(PREFIX, message);
227
+ }
228
+ }
229
+ }
230
+ };
231
+ var logger = new Logger();
232
+ function setLogLevel(level) {
233
+ logger.setLevel(level);
234
+ }
235
+
174
236
  // src/api/client.ts
175
237
  function getPlayerTruth(container) {
176
238
  if (typeof window === "undefined") {
@@ -220,6 +282,7 @@ var ApiClient = class {
220
282
  * The request is aborted after 10 seconds.
221
283
  */
222
284
  async fetchAds(deviceId, etag = null) {
285
+ logger.debug("Fetching ads", { deviceId });
223
286
  const headers = { Accept: "application/json" };
224
287
  if (etag) headers["If-None-Match"] = etag;
225
288
  const controller = new AbortController();
@@ -254,7 +317,7 @@ var ApiClient = class {
254
317
  }
255
318
  const data = await response.json();
256
319
  const newEtag = response.headers.get("ETag");
257
- return {
320
+ const result = {
258
321
  ads: data.data?.ads ?? [],
259
322
  settings: data.data?.settings ?? {},
260
323
  programmatic: data.data?.header_bidding_settings ?? null,
@@ -264,6 +327,8 @@ var ApiClient = class {
264
327
  etag: newEtag,
265
328
  notModified: false
266
329
  };
330
+ logger.debug("Ads fetched", { deviceId, count: result.ads.length, notModified: false });
331
+ return result;
267
332
  } catch (error) {
268
333
  clearTimeout(timeoutId);
269
334
  throw error;
@@ -279,6 +344,7 @@ var ApiClient = class {
279
344
  * Returns `true` if the server acknowledged the impression.
280
345
  */
281
346
  async reportImpression(impression) {
347
+ logger.debug("Reporting impression", { adId: impression.adid, impressionId: impression.impid });
282
348
  try {
283
349
  const params = new URLSearchParams({
284
350
  adid: impression.adid,
@@ -302,6 +368,7 @@ var ApiClient = class {
302
368
  * Returns `true` on 2xx, `false` on any error.
303
369
  */
304
370
  async sendHeartbeat(deviceId, screenId) {
371
+ logger.debug("Sending heartbeat", { deviceId });
305
372
  try {
306
373
  const response = await fetch(`${this.apiBase}/device/${deviceId}/heartbeat`, {
307
374
  method: "POST",
@@ -324,6 +391,7 @@ var ApiClient = class {
324
391
  * error, etc.) to the analytics backend.
325
392
  */
326
393
  async reportProgrammaticEvent(event) {
394
+ logger.debug("Reporting programmatic event", { eventType: event.eventType });
327
395
  try {
328
396
  const response = await fetch(`${this.apiBase}/programmatic-event`, {
329
397
  method: "POST",
@@ -1736,6 +1804,75 @@ var _TrillboardsAds = class _TrillboardsAds {
1736
1804
  _TrillboardsAds._instance = null;
1737
1805
  var TrillboardsAds = _TrillboardsAds;
1738
1806
 
1807
+ // src/errors.ts
1808
+ var TrillboardsError = class extends Error {
1809
+ constructor(message, options = {}) {
1810
+ super(message);
1811
+ this.name = "TrillboardsError";
1812
+ this.type = options.type ?? "api_error";
1813
+ this.code = options.code ?? "unknown_error";
1814
+ this.statusCode = options.statusCode ?? 500;
1815
+ this.help = options.help;
1816
+ this.param = options.param;
1817
+ }
1818
+ };
1819
+ var TrillboardsAuthenticationError = class extends TrillboardsError {
1820
+ constructor(message) {
1821
+ super(
1822
+ message ?? "Invalid API key. Check your key at https://trillboards.com/developers",
1823
+ {
1824
+ type: "authentication_error",
1825
+ code: "invalid_api_key",
1826
+ statusCode: 401,
1827
+ help: "https://trillboards.com/developers"
1828
+ }
1829
+ );
1830
+ this.name = "TrillboardsAuthenticationError";
1831
+ }
1832
+ };
1833
+ var TrillboardsRateLimitError = class extends TrillboardsError {
1834
+ constructor(retryAfter, message) {
1835
+ super(
1836
+ message ?? `Rate limit exceeded. Retry after ${retryAfter} seconds.`,
1837
+ {
1838
+ type: "rate_limit_error",
1839
+ code: "rate_limited",
1840
+ statusCode: 429
1841
+ }
1842
+ );
1843
+ this.name = "TrillboardsRateLimitError";
1844
+ this.retryAfter = retryAfter;
1845
+ }
1846
+ };
1847
+ var TrillboardsNotFoundError = class extends TrillboardsError {
1848
+ constructor(message) {
1849
+ super(
1850
+ message ?? "The requested resource was not found.",
1851
+ {
1852
+ type: "not_found_error",
1853
+ code: "resource_not_found",
1854
+ statusCode: 404,
1855
+ help: "Verify the ID is correct and belongs to your account."
1856
+ }
1857
+ );
1858
+ this.name = "TrillboardsNotFoundError";
1859
+ }
1860
+ };
1861
+ var TrillboardsValidationError = class extends TrillboardsError {
1862
+ constructor(message, param) {
1863
+ super(
1864
+ message ?? "The request was invalid.",
1865
+ {
1866
+ type: "validation_error",
1867
+ code: "invalid_request",
1868
+ statusCode: 400,
1869
+ param
1870
+ }
1871
+ );
1872
+ this.name = "TrillboardsValidationError";
1873
+ }
1874
+ };
1875
+
1739
1876
  exports.ApiClient = ApiClient;
1740
1877
  exports.CircuitBreaker = CircuitBreaker;
1741
1878
  exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
@@ -1744,9 +1881,16 @@ exports.EventEmitter = EventEmitter;
1744
1881
  exports.SDK_VERSION = SDK_VERSION;
1745
1882
  exports.Telemetry = Telemetry;
1746
1883
  exports.TrillboardsAds = TrillboardsAds;
1884
+ exports.TrillboardsAuthenticationError = TrillboardsAuthenticationError;
1885
+ exports.TrillboardsError = TrillboardsError;
1886
+ exports.TrillboardsNotFoundError = TrillboardsNotFoundError;
1887
+ exports.TrillboardsRateLimitError = TrillboardsRateLimitError;
1888
+ exports.TrillboardsValidationError = TrillboardsValidationError;
1747
1889
  exports.WaterfallEngine = WaterfallEngine;
1748
1890
  exports.createInitialState = createInitialState;
1749
1891
  exports.getPublicState = getPublicState;
1892
+ exports.logger = logger;
1750
1893
  exports.resolveConfig = resolveConfig;
1894
+ exports.setLogLevel = setLogLevel;
1751
1895
  //# sourceMappingURL=index.js.map
1752
1896
  //# sourceMappingURL=index.js.map