@the_ro_show/agent-ads-sdk 0.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/dist/index.js ADDED
@@ -0,0 +1,351 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ APIRequestError: () => APIRequestError,
24
+ AttentionMarketClient: () => AttentionMarketClient,
25
+ AttentionMarketError: () => AttentionMarketError,
26
+ NetworkError: () => NetworkError,
27
+ TimeoutError: () => TimeoutError,
28
+ createClickEvent: () => createClickEvent,
29
+ createImpressionEvent: () => createImpressionEvent,
30
+ createOpportunity: () => createOpportunity,
31
+ generateTimestamp: () => generateTimestamp,
32
+ generateUUID: () => generateUUID
33
+ });
34
+ module.exports = __toCommonJS(index_exports);
35
+
36
+ // src/errors.ts
37
+ var AttentionMarketError = class _AttentionMarketError extends Error {
38
+ constructor(message) {
39
+ super(message);
40
+ this.name = "AttentionMarketError";
41
+ Object.setPrototypeOf(this, _AttentionMarketError.prototype);
42
+ }
43
+ };
44
+ var APIRequestError = class _APIRequestError extends AttentionMarketError {
45
+ statusCode;
46
+ errorCode;
47
+ requestId;
48
+ details;
49
+ constructor(statusCode, apiError) {
50
+ super(apiError.message);
51
+ this.name = "APIRequestError";
52
+ this.statusCode = statusCode;
53
+ this.errorCode = apiError.error;
54
+ if (apiError.request_id !== void 0) {
55
+ this.requestId = apiError.request_id;
56
+ }
57
+ if (apiError.details !== void 0) {
58
+ this.details = apiError.details;
59
+ }
60
+ Object.setPrototypeOf(this, _APIRequestError.prototype);
61
+ }
62
+ };
63
+ var NetworkError = class _NetworkError extends AttentionMarketError {
64
+ cause;
65
+ constructor(message, cause) {
66
+ super(message);
67
+ this.name = "NetworkError";
68
+ if (cause !== void 0) {
69
+ this.cause = cause;
70
+ }
71
+ Object.setPrototypeOf(this, _NetworkError.prototype);
72
+ }
73
+ };
74
+ var TimeoutError = class _TimeoutError extends AttentionMarketError {
75
+ constructor(message = "Request timed out") {
76
+ super(message);
77
+ this.name = "TimeoutError";
78
+ Object.setPrototypeOf(this, _TimeoutError.prototype);
79
+ }
80
+ };
81
+
82
+ // src/http.ts
83
+ var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
84
+ var HTTPClient = class {
85
+ constructor(config) {
86
+ this.config = config;
87
+ }
88
+ async request(method, path, options = {}) {
89
+ const url = `${this.config.baseUrl}${path}`;
90
+ let lastError;
91
+ for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
92
+ try {
93
+ const response = await this.makeRequest(url, method, options);
94
+ return response;
95
+ } catch (error) {
96
+ lastError = error;
97
+ if (!this.shouldRetry(error, attempt)) {
98
+ throw error;
99
+ }
100
+ if (attempt < this.config.maxRetries) {
101
+ await this.backoff(attempt);
102
+ }
103
+ }
104
+ }
105
+ throw lastError;
106
+ }
107
+ async makeRequest(url, method, options) {
108
+ const controller = new AbortController();
109
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeoutMs);
110
+ try {
111
+ const headers = {
112
+ "Content-Type": "application/json",
113
+ ...options.headers
114
+ };
115
+ if (this.config.apiKey) {
116
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
117
+ }
118
+ if (options.idempotencyKey) {
119
+ headers["Idempotency-Key"] = options.idempotencyKey;
120
+ }
121
+ const response = await fetch(url, {
122
+ method,
123
+ headers,
124
+ body: options.body ? JSON.stringify(options.body) : void 0,
125
+ signal: controller.signal
126
+ });
127
+ clearTimeout(timeoutId);
128
+ if (!response.ok) {
129
+ const errorBody = await response.json().catch(() => ({
130
+ error: "unknown_error",
131
+ message: "Failed to parse error response",
132
+ request_id: "unknown"
133
+ }));
134
+ throw new APIRequestError(response.status, errorBody);
135
+ }
136
+ return await response.json();
137
+ } catch (error) {
138
+ clearTimeout(timeoutId);
139
+ if (error instanceof Error && error.name === "AbortError") {
140
+ throw new TimeoutError();
141
+ }
142
+ if (error instanceof APIRequestError) {
143
+ throw error;
144
+ }
145
+ throw new NetworkError("Network request failed", error);
146
+ }
147
+ }
148
+ shouldRetry(error, attempt) {
149
+ if (attempt >= this.config.maxRetries) {
150
+ return false;
151
+ }
152
+ if (error instanceof TimeoutError) {
153
+ return true;
154
+ }
155
+ if (error instanceof NetworkError) {
156
+ return true;
157
+ }
158
+ if (error instanceof APIRequestError) {
159
+ return RETRYABLE_STATUS_CODES.has(error.statusCode);
160
+ }
161
+ return false;
162
+ }
163
+ async backoff(attempt) {
164
+ const baseDelay = 100 * Math.pow(2, attempt);
165
+ const jitter = Math.random() * 100;
166
+ const delay = baseDelay + jitter;
167
+ await new Promise((resolve) => setTimeout(resolve, delay));
168
+ }
169
+ };
170
+
171
+ // src/utils.ts
172
+ var import_node_crypto = require("crypto");
173
+ function generateUUID() {
174
+ return (0, import_node_crypto.randomUUID)();
175
+ }
176
+ function generateTimestamp() {
177
+ return (/* @__PURE__ */ new Date()).toISOString();
178
+ }
179
+ function createOpportunity(params) {
180
+ const opportunity = {
181
+ intent: {
182
+ taxonomy: params.taxonomy
183
+ },
184
+ context: {
185
+ country: params.country,
186
+ language: params.language,
187
+ platform: params.platform
188
+ },
189
+ constraints: {
190
+ max_units: params.constraints?.max_units ?? 1,
191
+ allowed_unit_types: params.constraints?.allowed_unit_types ?? ["sponsored_suggestion"]
192
+ },
193
+ privacy: {
194
+ data_policy: params.privacy?.data_policy ?? "coarse_only"
195
+ }
196
+ };
197
+ if (params.query !== void 0) {
198
+ opportunity.intent.query = params.query;
199
+ }
200
+ if (params.region !== void 0) {
201
+ opportunity.context.region = params.region;
202
+ }
203
+ if (params.city !== void 0) {
204
+ opportunity.context.city = params.city;
205
+ }
206
+ if (params.constraints?.blocked_categories !== void 0) {
207
+ opportunity.constraints.blocked_categories = params.constraints.blocked_categories;
208
+ }
209
+ if (params.constraints?.max_title_chars !== void 0) {
210
+ opportunity.constraints.max_title_chars = params.constraints.max_title_chars;
211
+ }
212
+ if (params.constraints?.max_body_chars !== void 0) {
213
+ opportunity.constraints.max_body_chars = params.constraints.max_body_chars;
214
+ }
215
+ return opportunity;
216
+ }
217
+ function createImpressionEvent(params) {
218
+ const event = {
219
+ event_id: generateUUID(),
220
+ occurred_at: params.occurred_at ?? generateTimestamp(),
221
+ agent_id: params.agent_id,
222
+ request_id: params.request_id,
223
+ decision_id: params.decision_id,
224
+ unit_id: params.unit_id,
225
+ event_type: "impression",
226
+ tracking_token: params.tracking_token
227
+ };
228
+ if (params.metadata !== void 0) {
229
+ event.metadata = params.metadata;
230
+ }
231
+ return event;
232
+ }
233
+ function createClickEvent(params) {
234
+ const event = {
235
+ event_id: generateUUID(),
236
+ occurred_at: params.occurred_at ?? generateTimestamp(),
237
+ agent_id: params.agent_id,
238
+ request_id: params.request_id,
239
+ decision_id: params.decision_id,
240
+ unit_id: params.unit_id,
241
+ event_type: "click",
242
+ tracking_token: params.tracking_token
243
+ };
244
+ if (params.metadata !== void 0) {
245
+ event.metadata = {
246
+ ...params.metadata,
247
+ href: params.href
248
+ };
249
+ } else {
250
+ event.metadata = {
251
+ href: params.href
252
+ };
253
+ }
254
+ return event;
255
+ }
256
+
257
+ // src/client.ts
258
+ var DEFAULT_BASE_URL = "https://api.attentionmarket.ai";
259
+ var DEFAULT_TIMEOUT_MS = 4e3;
260
+ var DEFAULT_MAX_RETRIES = 2;
261
+ var AttentionMarketClient = class {
262
+ http;
263
+ constructor(config) {
264
+ this.http = new HTTPClient({
265
+ apiKey: config.apiKey,
266
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
267
+ timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
268
+ maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES
269
+ });
270
+ }
271
+ /**
272
+ * Request a sponsored unit decision for an agent opportunity.
273
+ * Returns the full DecideResponse including status, ttl_ms, and all units.
274
+ */
275
+ async decideRaw(request, options) {
276
+ const requestOptions = { body: request };
277
+ if (options?.idempotencyKey !== void 0) {
278
+ requestOptions.idempotencyKey = options.idempotencyKey;
279
+ }
280
+ return await this.http.request("POST", "/v1/decide", requestOptions);
281
+ }
282
+ /**
283
+ * Convenience wrapper around decideRaw().
284
+ * Returns null if status is no_fill, otherwise returns the first ad unit.
285
+ */
286
+ async decide(request, options) {
287
+ const response = await this.decideRaw(request, options);
288
+ if (response.status === "no_fill") {
289
+ return null;
290
+ }
291
+ return response.units[0] ?? null;
292
+ }
293
+ /**
294
+ * Report an event (impression, click, action, conversion, feedback).
295
+ */
296
+ async track(event) {
297
+ return await this.http.request("POST", "/v1/event", {
298
+ body: event
299
+ });
300
+ }
301
+ /**
302
+ * Convenience method to track an impression event.
303
+ * Creates an impression event using createImpressionEvent() and calls track().
304
+ */
305
+ async trackImpression(params) {
306
+ const event = createImpressionEvent(params);
307
+ return await this.track(event);
308
+ }
309
+ /**
310
+ * Convenience method to track a click event.
311
+ * Creates a click event using createClickEvent() and calls track().
312
+ */
313
+ async trackClick(params) {
314
+ const event = createClickEvent(params);
315
+ return await this.track(event);
316
+ }
317
+ /**
318
+ * Fetch default policy constraints and formatting requirements.
319
+ */
320
+ async getPolicy() {
321
+ return await this.http.request("GET", "/v1/policy");
322
+ }
323
+ /**
324
+ * Create or register an agent (optional helper).
325
+ * Note: This endpoint is unauthenticated in v1.
326
+ */
327
+ static async signupAgent(request, options) {
328
+ const http = new HTTPClient({
329
+ baseUrl: options?.baseUrl ?? DEFAULT_BASE_URL,
330
+ timeoutMs: DEFAULT_TIMEOUT_MS,
331
+ maxRetries: DEFAULT_MAX_RETRIES
332
+ });
333
+ return await http.request("POST", "/v1/agent/signup", {
334
+ body: request
335
+ });
336
+ }
337
+ };
338
+ // Annotate the CommonJS export names for ESM import in node:
339
+ 0 && (module.exports = {
340
+ APIRequestError,
341
+ AttentionMarketClient,
342
+ AttentionMarketError,
343
+ NetworkError,
344
+ TimeoutError,
345
+ createClickEvent,
346
+ createImpressionEvent,
347
+ createOpportunity,
348
+ generateTimestamp,
349
+ generateUUID
350
+ });
351
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["/**\n * AttentionMarket Agent Ads SDK\n * TypeScript SDK for integrating agent-native sponsored units\n */\n\n// Main client\nexport { AttentionMarketClient } from './client.js';\n\n// Types\nexport type {\n // Configuration\n SDKConfig,\n // Agent Signup\n AgentSignupRequest,\n AgentSignupResponse,\n // Decide\n DecideRequest,\n DecideResponse,\n // Placement\n PlacementType,\n Placement,\n // Opportunity\n Opportunity,\n Intent,\n Context,\n Constraints,\n Privacy,\n // Ad Units\n AdUnit,\n Disclosure,\n Tracking,\n SponsoredSuggestion,\n SponsoredTool,\n ToolCall,\n // Events\n EventType,\n EventIngestRequest,\n EventIngestResponse,\n // Policy\n PolicyResponse,\n // Errors\n APIError,\n} from './types.js';\n\n// Errors\nexport {\n AttentionMarketError,\n APIRequestError,\n NetworkError,\n TimeoutError,\n} from './errors.js';\n\n// Utilities\nexport {\n generateUUID,\n generateTimestamp,\n createOpportunity,\n createImpressionEvent,\n createClickEvent,\n} from './utils.js';\n\nexport type {\n CreateOpportunityParams,\n CreateImpressionEventParams,\n CreateClickEventParams,\n} from './utils.js';\n","/**\n * Error classes for AttentionMarket SDK.\n * Surfaces HTTP status, API error codes, messages, and request_id.\n */\n\nimport type { APIError } from './types.js';\n\nexport class AttentionMarketError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'AttentionMarketError';\n Object.setPrototypeOf(this, AttentionMarketError.prototype);\n }\n}\n\nexport class APIRequestError extends AttentionMarketError {\n public readonly statusCode: number;\n public readonly errorCode: string;\n public readonly requestId?: string;\n public readonly details?: Record<string, unknown>;\n\n constructor(\n statusCode: number,\n apiError: APIError,\n ) {\n super(apiError.message);\n this.name = 'APIRequestError';\n this.statusCode = statusCode;\n this.errorCode = apiError.error;\n if (apiError.request_id !== undefined) {\n this.requestId = apiError.request_id;\n }\n if (apiError.details !== undefined) {\n this.details = apiError.details;\n }\n Object.setPrototypeOf(this, APIRequestError.prototype);\n }\n}\n\nexport class NetworkError extends AttentionMarketError {\n public readonly cause?: Error;\n\n constructor(message: string, cause?: Error) {\n super(message);\n this.name = 'NetworkError';\n if (cause !== undefined) {\n this.cause = cause;\n }\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n}\n\nexport class TimeoutError extends AttentionMarketError {\n constructor(message: string = 'Request timed out') {\n super(message);\n this.name = 'TimeoutError';\n Object.setPrototypeOf(this, TimeoutError.prototype);\n }\n}\n","/**\n * HTTP client with retry logic, timeout handling, and authentication.\n * Retry policy: only on 408, 429, 500, 502, 503, 504\n * Max retries: 2 (configurable)\n * Backoff: exponential with jitter\n */\n\nimport { APIRequestError, NetworkError, TimeoutError } from './errors.js';\nimport type { APIError } from './types.js';\n\nexport interface HTTPClientConfig {\n apiKey?: string;\n baseUrl: string;\n timeoutMs: number;\n maxRetries: number;\n}\n\nconst RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\n\nexport class HTTPClient {\n constructor(private config: HTTPClientConfig) {}\n\n async request<T>(\n method: 'GET' | 'POST',\n path: string,\n options: {\n body?: unknown;\n headers?: Record<string, string>;\n idempotencyKey?: string;\n } = {},\n ): Promise<T> {\n const url = `${this.config.baseUrl}${path}`;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await this.makeRequest(url, method, options);\n return response as T;\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry if it's not a retryable error\n if (!this.shouldRetry(error, attempt)) {\n throw error;\n }\n\n // Wait before retrying\n if (attempt < this.config.maxRetries) {\n await this.backoff(attempt);\n }\n }\n }\n\n // All retries exhausted\n throw lastError;\n }\n\n private async makeRequest(\n url: string,\n method: 'GET' | 'POST',\n options: {\n body?: unknown;\n headers?: Record<string, string>;\n idempotencyKey?: string;\n },\n ): Promise<unknown> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeoutMs);\n\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n\n if (this.config.apiKey) {\n headers['Authorization'] = `Bearer ${this.config.apiKey}`;\n }\n\n if (options.idempotencyKey) {\n headers['Idempotency-Key'] = options.idempotencyKey;\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Handle non-OK responses\n if (!response.ok) {\n const errorBody = await response.json().catch(() => ({\n error: 'unknown_error',\n message: 'Failed to parse error response',\n request_id: 'unknown',\n }));\n\n throw new APIRequestError(response.status, errorBody as APIError);\n }\n\n // Parse successful response\n return await response.json();\n } catch (error) {\n clearTimeout(timeoutId);\n\n // Handle abort (timeout)\n if (error instanceof Error && error.name === 'AbortError') {\n throw new TimeoutError();\n }\n\n // Re-throw API errors\n if (error instanceof APIRequestError) {\n throw error;\n }\n\n // Network errors\n throw new NetworkError('Network request failed', error as Error);\n }\n }\n\n private shouldRetry(error: unknown, attempt: number): boolean {\n // Don't retry if we've exhausted attempts\n if (attempt >= this.config.maxRetries) {\n return false;\n }\n\n // Retry on timeout\n if (error instanceof TimeoutError) {\n return true;\n }\n\n // Retry on network errors\n if (error instanceof NetworkError) {\n return true;\n }\n\n // Retry on specific HTTP status codes\n if (error instanceof APIRequestError) {\n return RETRYABLE_STATUS_CODES.has(error.statusCode);\n }\n\n return false;\n }\n\n private async backoff(attempt: number): Promise<void> {\n // Exponential backoff: 100ms * 2^attempt + jitter\n const baseDelay = 100 * Math.pow(2, attempt);\n const jitter = Math.random() * 100;\n const delay = baseDelay + jitter;\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n","/**\n * Utility functions for the AttentionMarket SDK.\n * Includes UUID generation, opportunity helpers, and event builders.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { EventIngestRequest, Opportunity } from './types.js';\n\n/**\n * Generate a UUID v4 for use as event_id, request_id, etc.\n */\nexport function generateUUID(): string {\n return randomUUID();\n}\n\n/**\n * Generate an ISO 8601 timestamp for the current moment.\n */\nexport function generateTimestamp(): string {\n return new Date().toISOString();\n}\n\n// ============================================================================\n// Opportunity Helper\n// ============================================================================\n\nexport interface CreateOpportunityParams {\n // Required\n taxonomy: string;\n country: string;\n language: string;\n platform: 'web' | 'ios' | 'android' | 'desktop' | 'voice' | 'other';\n\n // Optional\n query?: string;\n region?: string;\n city?: string;\n\n // Optional overrides (with defaults)\n constraints?: {\n max_units?: number;\n allowed_unit_types?: ('sponsored_suggestion' | 'sponsored_block' | 'sponsored_tool')[];\n blocked_categories?: string[];\n max_title_chars?: number;\n max_body_chars?: number;\n };\n privacy?: {\n data_policy?: 'coarse_only' | 'none' | 'extended';\n };\n}\n\n/**\n * Create a valid Opportunity object with safe defaults.\n *\n * Defaults:\n * - constraints.max_units = 1\n * - constraints.allowed_unit_types = ['sponsored_suggestion']\n * - privacy.data_policy = 'coarse_only'\n */\nexport function createOpportunity(params: CreateOpportunityParams): Opportunity {\n const opportunity: Opportunity = {\n intent: {\n taxonomy: params.taxonomy,\n },\n context: {\n country: params.country,\n language: params.language,\n platform: params.platform,\n },\n constraints: {\n max_units: params.constraints?.max_units ?? 1,\n allowed_unit_types: params.constraints?.allowed_unit_types ?? ['sponsored_suggestion'],\n },\n privacy: {\n data_policy: params.privacy?.data_policy ?? 'coarse_only',\n },\n };\n\n // Add optional intent fields\n if (params.query !== undefined) {\n opportunity.intent.query = params.query;\n }\n\n // Add optional context fields\n if (params.region !== undefined) {\n opportunity.context.region = params.region;\n }\n if (params.city !== undefined) {\n opportunity.context.city = params.city;\n }\n\n // Add optional constraint fields\n if (params.constraints?.blocked_categories !== undefined) {\n opportunity.constraints.blocked_categories = params.constraints.blocked_categories;\n }\n if (params.constraints?.max_title_chars !== undefined) {\n opportunity.constraints.max_title_chars = params.constraints.max_title_chars;\n }\n if (params.constraints?.max_body_chars !== undefined) {\n opportunity.constraints.max_body_chars = params.constraints.max_body_chars;\n }\n\n return opportunity;\n}\n\n// ============================================================================\n// Event Helpers\n// ============================================================================\n\nexport interface CreateImpressionEventParams {\n agent_id: string;\n request_id: string;\n decision_id: string;\n unit_id: string;\n tracking_token: string;\n occurred_at?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Helper to create an impression event payload.\n *\n * @param params - Event parameters (snake_case to match API)\n * @returns EventIngestRequest ready to pass to client.track()\n */\nexport function createImpressionEvent(params: CreateImpressionEventParams): EventIngestRequest {\n const event: EventIngestRequest = {\n event_id: generateUUID(),\n occurred_at: params.occurred_at ?? generateTimestamp(),\n agent_id: params.agent_id,\n request_id: params.request_id,\n decision_id: params.decision_id,\n unit_id: params.unit_id,\n event_type: 'impression',\n tracking_token: params.tracking_token,\n };\n\n if (params.metadata !== undefined) {\n event.metadata = params.metadata;\n }\n\n return event;\n}\n\nexport interface CreateClickEventParams {\n agent_id: string;\n request_id: string;\n decision_id: string;\n unit_id: string;\n tracking_token: string;\n href: string;\n occurred_at?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Helper to create a click event payload.\n *\n * @param params - Event parameters (snake_case to match API)\n * @returns EventIngestRequest ready to pass to client.track()\n */\nexport function createClickEvent(params: CreateClickEventParams): EventIngestRequest {\n const event: EventIngestRequest = {\n event_id: generateUUID(),\n occurred_at: params.occurred_at ?? generateTimestamp(),\n agent_id: params.agent_id,\n request_id: params.request_id,\n decision_id: params.decision_id,\n unit_id: params.unit_id,\n event_type: 'click',\n tracking_token: params.tracking_token,\n };\n\n // Include href in metadata\n if (params.metadata !== undefined) {\n event.metadata = {\n ...params.metadata,\n href: params.href,\n };\n } else {\n event.metadata = {\n href: params.href,\n };\n }\n\n return event;\n}\n","/**\n * Main SDK client for AttentionMarket Agent Ads API.\n * Provides public methods: decide(), decideRaw(), track(), getPolicy(), signupAgent()\n */\n\nimport { HTTPClient } from './http.js';\nimport { createImpressionEvent, createClickEvent } from './utils.js';\nimport type {\n SDKConfig,\n DecideRequest,\n DecideResponse,\n EventIngestRequest,\n EventIngestResponse,\n PolicyResponse,\n AgentSignupRequest,\n AgentSignupResponse,\n AdUnit,\n} from './types.js';\nimport type { CreateImpressionEventParams, CreateClickEventParams } from './utils.js';\n\nconst DEFAULT_BASE_URL = 'https://api.attentionmarket.ai';\nconst DEFAULT_TIMEOUT_MS = 4000;\nconst DEFAULT_MAX_RETRIES = 2;\n\nexport class AttentionMarketClient {\n private http: HTTPClient;\n\n constructor(config: SDKConfig) {\n this.http = new HTTPClient({\n apiKey: config.apiKey,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n });\n }\n\n /**\n * Request a sponsored unit decision for an agent opportunity.\n * Returns the full DecideResponse including status, ttl_ms, and all units.\n */\n async decideRaw(\n request: DecideRequest,\n options?: { idempotencyKey?: string },\n ): Promise<DecideResponse> {\n const requestOptions: {\n body: DecideRequest;\n idempotencyKey?: string;\n } = { body: request };\n\n if (options?.idempotencyKey !== undefined) {\n requestOptions.idempotencyKey = options.idempotencyKey;\n }\n\n return await this.http.request<DecideResponse>('POST', '/v1/decide', requestOptions);\n }\n\n /**\n * Convenience wrapper around decideRaw().\n * Returns null if status is no_fill, otherwise returns the first ad unit.\n */\n async decide(\n request: DecideRequest,\n options?: { idempotencyKey?: string },\n ): Promise<AdUnit | null> {\n const response = await this.decideRaw(request, options);\n\n if (response.status === 'no_fill') {\n return null;\n }\n\n // Return first unit if available\n return response.units[0] ?? null;\n }\n\n /**\n * Report an event (impression, click, action, conversion, feedback).\n */\n async track(event: EventIngestRequest): Promise<EventIngestResponse> {\n return await this.http.request<EventIngestResponse>('POST', '/v1/event', {\n body: event,\n });\n }\n\n /**\n * Convenience method to track an impression event.\n * Creates an impression event using createImpressionEvent() and calls track().\n */\n async trackImpression(\n params: Omit<CreateImpressionEventParams, 'occurred_at'> & { occurred_at?: string },\n ): Promise<EventIngestResponse> {\n const event = createImpressionEvent(params);\n return await this.track(event);\n }\n\n /**\n * Convenience method to track a click event.\n * Creates a click event using createClickEvent() and calls track().\n */\n async trackClick(\n params: Omit<CreateClickEventParams, 'occurred_at'> & { occurred_at?: string },\n ): Promise<EventIngestResponse> {\n const event = createClickEvent(params);\n return await this.track(event);\n }\n\n /**\n * Fetch default policy constraints and formatting requirements.\n */\n async getPolicy(): Promise<PolicyResponse> {\n return await this.http.request<PolicyResponse>('GET', '/v1/policy');\n }\n\n /**\n * Create or register an agent (optional helper).\n * Note: This endpoint is unauthenticated in v1.\n */\n static async signupAgent(\n request: AgentSignupRequest,\n options?: { baseUrl?: string },\n ): Promise<AgentSignupResponse> {\n // Create temporary HTTP client without authentication\n const http = new HTTPClient({\n baseUrl: options?.baseUrl ?? DEFAULT_BASE_URL,\n timeoutMs: DEFAULT_TIMEOUT_MS,\n maxRetries: DEFAULT_MAX_RETRIES,\n });\n\n return await http.request<AgentSignupResponse>('POST', '/v1/agent/signup', {\n body: request,\n });\n }\n}\n"],"mappings":"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","names":[]}