@adzenai/ai 1.1.1 → 1.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.
@@ -21,8 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var react_exports = {};
22
22
  __export(react_exports, {
23
23
  AdzenCard: () => AdzenCard,
24
+ InlineAd: () => InlineAd,
25
+ buildInlineAdSegments: () => buildInlineAdSegments,
26
+ dispatchInlineAdEvent: () => dispatchInlineAdEvent,
24
27
  dispatchPlacementEvent: () => dispatchPlacementEvent,
25
28
  dispatchPlacementEvents: () => dispatchPlacementEvents,
29
+ useAdzenInlineAds: () => useAdzenInlineAds,
26
30
  useAdzenPlacement: () => useAdzenPlacement
27
31
  });
28
32
  module.exports = __toCommonJS(react_exports);
@@ -220,13 +224,194 @@ var cardStyles = {
220
224
  }
221
225
  };
222
226
 
227
+ // src/copilotkit/react/InlineAd.tsx
228
+ var import_react3 = require("react");
229
+ var import_core2 = require("@adzenai/core");
230
+ var import_jsx_runtime2 = require("react/jsx-runtime");
231
+ function fireBeacon2(url) {
232
+ fetch(url, { method: "GET", keepalive: true }).catch(() => {
233
+ setTimeout(() => {
234
+ fetch(url, { method: "GET", keepalive: true }).catch(() => {
235
+ });
236
+ }, 1e3);
237
+ });
238
+ }
239
+ function InlineAd({
240
+ ad,
241
+ viewabilityThresholdMs = 1e3,
242
+ className
243
+ }) {
244
+ const ref = (0, import_react3.useRef)(null);
245
+ const [renderFired, setRenderFired] = (0, import_react3.useState)(false);
246
+ const [viewed, setViewed] = (0, import_react3.useState)(false);
247
+ (0, import_react3.useEffect)(() => {
248
+ if (renderFired || !ad.tracking.impression_url) return;
249
+ setRenderFired(true);
250
+ const url = new URL(ad.tracking.impression_url);
251
+ url.searchParams.set("timestamp", (/* @__PURE__ */ new Date()).toISOString());
252
+ fireBeacon2(url.toString());
253
+ }, [ad, renderFired]);
254
+ (0, import_react3.useEffect)(() => {
255
+ if (!ref.current || viewed || !ad.tracking.impression_url) return;
256
+ return (0, import_core2.observeViewability)({
257
+ element: ref.current,
258
+ thresholdMs: viewabilityThresholdMs,
259
+ onViewed: () => {
260
+ setViewed(true);
261
+ if (!ad.tracking.impression_url) return;
262
+ const url = new URL(ad.tracking.impression_url);
263
+ url.searchParams.set("type", "view");
264
+ url.searchParams.set("viewability_ms", String(viewabilityThresholdMs));
265
+ url.searchParams.set("timestamp", (/* @__PURE__ */ new Date()).toISOString());
266
+ fireBeacon2(url.toString());
267
+ }
268
+ });
269
+ }, [ad, viewed, viewabilityThresholdMs]);
270
+ const advertiser = ad.creative.advertiser_name ?? ad.creative.headline;
271
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref, className, style: inlineStyles.wrapper, children: [
272
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: inlineStyles.badge, "aria-label": "Advertisement", children: "Ad" }),
273
+ advertiser ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: inlineStyles.advertiser, children: [
274
+ advertiser,
275
+ " "
276
+ ] }) : null,
277
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
278
+ "a",
279
+ {
280
+ href: ad.creative.destination_url,
281
+ target: "_blank",
282
+ rel: "noopener sponsored",
283
+ style: inlineStyles.cta,
284
+ children: ad.creative.cta_text
285
+ }
286
+ )
287
+ ] });
288
+ }
289
+ var inlineStyles = {
290
+ // Block-level so the snippet starts on its own line below the text it
291
+ // follows, but otherwise plain: no border, background, or padding.
292
+ wrapper: {
293
+ display: "block",
294
+ margin: "0.5rem 0",
295
+ fontSize: "0.9em",
296
+ lineHeight: 1.5
297
+ },
298
+ badge: {
299
+ display: "inline-block",
300
+ marginRight: "0.4em",
301
+ padding: "0.1em 0.4em",
302
+ borderRadius: 4,
303
+ background: "#30363d",
304
+ color: "#8b949e",
305
+ fontSize: "0.75em",
306
+ fontWeight: 700,
307
+ letterSpacing: "0.05em",
308
+ textTransform: "uppercase",
309
+ verticalAlign: "middle"
310
+ },
311
+ advertiser: {
312
+ color: "#8b949e"
313
+ },
314
+ cta: {
315
+ color: "#58a6ff",
316
+ textDecoration: "none",
317
+ fontWeight: 500
318
+ }
319
+ };
320
+
321
+ // src/copilotkit/react/useAdzenInlineAds.ts
322
+ var import_react4 = require("react");
323
+ function readOffset(payload) {
324
+ return typeof payload.content_offset === "number" ? payload.content_offset : Number.MAX_SAFE_INTEGER;
325
+ }
326
+ var PARAGRAPH_BREAK = /\n[ \t]*\n/;
327
+ var ENDS_ON_PARAGRAPH_BREAK = /\n[ \t]*\n$/;
328
+ function snapToParagraphEnd(content, offset) {
329
+ if (offset >= content.length) return content.length;
330
+ if (ENDS_ON_PARAGRAPH_BREAK.test(content.slice(0, offset))) return offset;
331
+ return nextParagraphEnd(content, Math.max(0, offset - 1));
332
+ }
333
+ function nextParagraphEnd(content, from) {
334
+ if (from >= content.length) return content.length;
335
+ const match = PARAGRAPH_BREAK.exec(content.slice(from));
336
+ return match ? from + match.index + match[0].length : content.length;
337
+ }
338
+ function buildInlineAdSegments(content, ads) {
339
+ if (ads.length === 0) {
340
+ return content ? [{ kind: "text", text: content }] : [];
341
+ }
342
+ const segments = [];
343
+ let cursor = 0;
344
+ let lastAnchor = -1;
345
+ for (const ad of ads) {
346
+ let anchor = snapToParagraphEnd(content, Math.max(ad.content_offset, 0));
347
+ if (anchor <= lastAnchor) anchor = nextParagraphEnd(content, lastAnchor);
348
+ if (anchor <= lastAnchor) continue;
349
+ if (anchor > cursor) {
350
+ segments.push({ kind: "text", text: content.slice(cursor, anchor) });
351
+ }
352
+ segments.push({ kind: "ad", ad });
353
+ cursor = anchor;
354
+ lastAnchor = anchor;
355
+ }
356
+ if (cursor < content.length) {
357
+ segments.push({ kind: "text", text: content.slice(cursor) });
358
+ }
359
+ return segments;
360
+ }
361
+ function useAdzenInlineAds() {
362
+ const [adsMap, setAdsMap] = (0, import_react4.useState)(
363
+ () => /* @__PURE__ */ new Map()
364
+ );
365
+ (0, import_react4.useEffect)(() => {
366
+ function handler(e) {
367
+ const detail = e.detail;
368
+ if (!detail || typeof detail !== "object") return;
369
+ const payload = detail;
370
+ const messageId = payload.message_id;
371
+ if (!messageId) return;
372
+ const anchored = {
373
+ ...payload,
374
+ message_id: messageId,
375
+ content_offset: readOffset(payload)
376
+ };
377
+ setAdsMap((prev) => {
378
+ const existing = prev.get(messageId) ?? [];
379
+ if (existing.some((a) => a.ad_id === anchored.ad_id)) return prev;
380
+ const next = new Map(prev);
381
+ next.set(
382
+ messageId,
383
+ [...existing, anchored].sort(
384
+ (a, b) => a.content_offset - b.content_offset
385
+ )
386
+ );
387
+ return next;
388
+ });
389
+ }
390
+ window.addEventListener("adzen_inline_ad", handler);
391
+ return () => window.removeEventListener("adzen_inline_ad", handler);
392
+ }, []);
393
+ const getInlineAdsForMessage = (0, import_react4.useCallback)(
394
+ (messageId) => {
395
+ return adsMap.get(messageId) ?? [];
396
+ },
397
+ [adsMap]
398
+ );
399
+ const getInlineAdSegments = (0, import_react4.useCallback)(
400
+ (messageId, content) => buildInlineAdSegments(content, adsMap.get(messageId) ?? []),
401
+ [adsMap]
402
+ );
403
+ return { getInlineAdsForMessage, getInlineAdSegments };
404
+ }
405
+
223
406
  // src/copilotkit/react/bridge.ts
407
+ function isCustomEvent(event) {
408
+ const type = String(event.type ?? "");
409
+ return type === "CUSTOM_EVENT" || type === "CUSTOM" || type === "CustomEvent";
410
+ }
224
411
  function dispatchPlacementEvent(event) {
225
412
  if (typeof window === "undefined") return false;
226
413
  if (event.name !== "adzen_placement") return false;
227
- const type = String(event.type ?? "");
228
- if (type !== "CUSTOM_EVENT" && type !== "CUSTOM" && type !== "CustomEvent")
229
- return false;
414
+ if (!isCustomEvent(event)) return false;
230
415
  const value = event.value;
231
416
  if (!value) return false;
232
417
  window.dispatchEvent(
@@ -234,16 +419,32 @@ function dispatchPlacementEvent(event) {
234
419
  );
235
420
  return true;
236
421
  }
422
+ function dispatchInlineAdEvent(event) {
423
+ if (typeof window === "undefined") return false;
424
+ if (event.name !== "adzen_inline_ad") return false;
425
+ if (!isCustomEvent(event)) return false;
426
+ const value = event.value;
427
+ if (!value) return false;
428
+ window.dispatchEvent(
429
+ new CustomEvent("adzen_inline_ad", { detail: value })
430
+ );
431
+ return true;
432
+ }
237
433
  function dispatchPlacementEvents(events) {
238
434
  for (const event of events) {
239
435
  dispatchPlacementEvent(event);
436
+ dispatchInlineAdEvent(event);
240
437
  }
241
438
  }
242
439
  // Annotate the CommonJS export names for ESM import in node:
243
440
  0 && (module.exports = {
244
441
  AdzenCard,
442
+ InlineAd,
443
+ buildInlineAdSegments,
444
+ dispatchInlineAdEvent,
245
445
  dispatchPlacementEvent,
246
446
  dispatchPlacementEvents,
447
+ useAdzenInlineAds,
247
448
  useAdzenPlacement
248
449
  });
249
450
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/copilotkit/react/index.ts","../../../src/copilotkit/react/AdzenCard.tsx","../../../src/copilotkit/react/useAdzenPlacement.ts","../../../src/copilotkit/react/bridge.ts"],"sourcesContent":["export { AdzenCard } from \"./AdzenCard.js\";\nexport type { AdzenCardProps } from \"./AdzenCard.js\";\nexport { useAdzenPlacement } from \"./useAdzenPlacement.js\";\nexport type { UseAdzenPlacementReturn } from \"./useAdzenPlacement.js\";\nexport { dispatchPlacementEvent, dispatchPlacementEvents } from \"./bridge.js\";\n","import { useRef, useEffect, useState } from \"react\";\nimport { observeViewability } from \"@adzenai/core\";\nimport { useAdzenPlacement } from \"./useAdzenPlacement.js\";\n\nexport interface AdzenCardProps {\n messageId: string;\n adUnitPosition?: string;\n viewabilityThresholdMs?: number;\n className?: string;\n}\n\nfunction fireBeacon(url: string): void {\n fetch(url, { method: \"GET\", keepalive: true }).catch(() => {\n setTimeout(() => {\n fetch(url, { method: \"GET\", keepalive: true }).catch(() => {});\n }, 1000);\n });\n}\n\n/**\n * Renders a sponsored ad card for a given assistant message. Returns `null`\n * (no DOM output) when there is no ad for the message.\n */\nexport function AdzenCard({\n messageId,\n adUnitPosition = \"chin\",\n viewabilityThresholdMs = 1000,\n className,\n}: AdzenCardProps) {\n const { getAdForMessage } = useAdzenPlacement();\n const ad = getAdForMessage(messageId);\n const cardRef = useRef<HTMLDivElement>(null);\n const [renderFired, setRenderFired] = useState(false);\n const [viewed, setViewed] = useState(false);\n\n useEffect(() => {\n if (!ad || renderFired || !ad.render_impression_url) return;\n setRenderFired(true);\n\n const url = new URL(ad.render_impression_url);\n url.searchParams.set(\"ad_unit_position\", adUnitPosition);\n url.searchParams.set(\"timestamp\", new Date().toISOString());\n fireBeacon(url.toString());\n }, [ad, renderFired, adUnitPosition]);\n\n useEffect(() => {\n if (!ad || !cardRef.current || viewed || !ad.view_impression_url) return;\n\n return observeViewability({\n element: cardRef.current,\n thresholdMs: viewabilityThresholdMs,\n onViewed: () => {\n setViewed(true);\n if (!ad.view_impression_url) return;\n const url = new URL(ad.view_impression_url);\n url.searchParams.set(\"ad_unit_position\", adUnitPosition);\n url.searchParams.set(\"viewability_ms\", String(viewabilityThresholdMs));\n url.searchParams.set(\"timestamp\", new Date().toISOString());\n fireBeacon(url.toString());\n },\n });\n }, [ad, viewed, adUnitPosition, viewabilityThresholdMs]);\n\n if (!ad) return null;\n\n const initial = ad.advertiser_name?.charAt(0).toUpperCase() ?? \"?\";\n\n return (\n <div\n ref={cardRef}\n className={className}\n data-adzen-ad-unit-position={adUnitPosition}\n style={cardStyles.wrapper}\n >\n <div style={cardStyles.avatar}>\n {ad.advertiser_image_url ? (\n <img\n src={ad.advertiser_image_url}\n alt={ad.advertiser_name}\n style={cardStyles.avatarImg}\n />\n ) : (\n <span style={cardStyles.avatarLetter}>{initial}</span>\n )}\n </div>\n\n <div style={cardStyles.content}>\n <div style={cardStyles.topRow}>\n <span style={cardStyles.advertiserName}>{ad.advertiser_name}</span>\n <span style={cardStyles.relevantAd}>Relevant Ad</span>\n </div>\n <div style={cardStyles.bottomRow}>\n <span style={cardStyles.headline}>{ad.headline}</span>\n <a\n href={ad.destination_url}\n target=\"_blank\"\n rel=\"noopener sponsored\"\n style={cardStyles.cta}\n >\n {ad.cta_text}\n </a>\n </div>\n </div>\n </div>\n );\n}\n\nconst cardStyles: Record<string, React.CSSProperties> = {\n wrapper: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.625rem\",\n fontSize: \"0.85rem\",\n padding: \"0.625rem 0.75rem\",\n },\n avatar: {\n width: 32,\n height: 32,\n borderRadius: \"50%\",\n background: \"#d1d5db\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n overflow: \"hidden\",\n },\n avatarImg: {\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\" as const,\n borderRadius: \"50%\",\n },\n avatarLetter: {\n fontSize: \"0.8rem\",\n fontWeight: 700,\n color: \"#374151\",\n lineHeight: 1,\n },\n content: {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"0.125rem\",\n minWidth: 0,\n },\n topRow: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n },\n advertiserName: {\n fontWeight: 700,\n color: \"inherit\",\n },\n relevantAd: {\n color: \"#8b949e\",\n fontSize: \"0.8rem\",\n },\n bottomRow: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n whiteSpace: \"nowrap\" as const,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n },\n headline: {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n },\n cta: {\n color: \"#58a6ff\",\n textDecoration: \"none\",\n fontWeight: 500,\n flexShrink: 0,\n },\n};\n","import { useState, useEffect, useCallback } from \"react\";\nimport type { AdzenPlacement } from \"@adzenai/core\";\n\nexport interface UseAdzenPlacementReturn {\n getAdForMessage(messageId: string): AdzenPlacement | null;\n placements: Map<string, AdzenPlacement>;\n}\n\n/**\n * React hook that subscribes to `adzen_placement` custom events and\n * maintains a map of messageId -> AdzenPlacement.\n *\n * Works anywhere in the React tree below `<CopilotKit>` — no wrapper\n * provider required.\n */\nexport function useAdzenPlacement(): UseAdzenPlacementReturn {\n const [placements, setPlacements] = useState<Map<string, AdzenPlacement>>(\n () => new Map(),\n );\n\n useEffect(() => {\n function handler(e: Event) {\n const detail = (e as CustomEvent).detail;\n if (!detail || typeof detail !== \"object\") return;\n\n const placement = detail as AdzenPlacement & { message_id?: string };\n const messageId = placement.message_id;\n if (!messageId) return;\n\n setPlacements((prev) => {\n const existing = prev.get(messageId);\n if (existing && existing.ad_id === placement.ad_id) return prev;\n const next = new Map(prev);\n next.set(messageId, placement);\n return next;\n });\n }\n\n window.addEventListener(\"adzen_placement\", handler);\n return () => window.removeEventListener(\"adzen_placement\", handler);\n }, []);\n\n const getAdForMessage = useCallback(\n (messageId: string): AdzenPlacement | null => {\n return placements.get(messageId) ?? null;\n },\n [placements],\n );\n\n return { getAdForMessage, placements };\n}\n","import type { AdzenPlacement } from \"@adzenai/core\";\n\n/**\n * Checks whether an AG-UI event is an `adzen_placement` custom event\n * and, if so, dispatches it as a browser `CustomEvent` on `window`\n * so that `useAdzenPlacement` can pick it up.\n *\n * Call this for every event returned by `AdzenAsyncMiddleware.processEvent()`.\n * Non-placement events are silently ignored.\n */\nexport function dispatchPlacementEvent(\n event: Record<string, unknown>,\n): boolean {\n if (typeof window === \"undefined\") return false;\n if (event.name !== \"adzen_placement\") return false;\n\n const type = String(event.type ?? \"\");\n if (type !== \"CUSTOM_EVENT\" && type !== \"CUSTOM\" && type !== \"CustomEvent\")\n return false;\n\n const value = event.value as (AdzenPlacement & { message_id?: string }) | undefined;\n if (!value) return false;\n\n window.dispatchEvent(\n new CustomEvent(\"adzen_placement\", { detail: value }),\n );\n return true;\n}\n\n/**\n * Convenience wrapper: iterates an array of AG-UI events (as returned by\n * `AdzenAsyncMiddleware.processEvent()`) and dispatches any placement\n * events to the browser.\n */\nexport function dispatchPlacementEvents(\n events: Record<string, unknown>[],\n): void {\n for (const event of events) {\n dispatchPlacementEvent(event);\n }\n}\n"],"mappings":"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","names":["import_react"]}
1
+ {"version":3,"sources":["../../../src/copilotkit/react/index.ts","../../../src/copilotkit/react/AdzenCard.tsx","../../../src/copilotkit/react/useAdzenPlacement.ts","../../../src/copilotkit/react/InlineAd.tsx","../../../src/copilotkit/react/useAdzenInlineAds.ts","../../../src/copilotkit/react/bridge.ts"],"sourcesContent":["export { AdzenCard } from \"./AdzenCard.js\";\nexport type { AdzenCardProps } from \"./AdzenCard.js\";\nexport { InlineAd } from \"./InlineAd.js\";\nexport type { InlineAdProps } from \"./InlineAd.js\";\nexport { useAdzenPlacement } from \"./useAdzenPlacement.js\";\nexport type { UseAdzenPlacementReturn } from \"./useAdzenPlacement.js\";\nexport {\n useAdzenInlineAds,\n buildInlineAdSegments,\n} from \"./useAdzenInlineAds.js\";\nexport type {\n UseAdzenInlineAdsReturn,\n InlineAdSegment,\n} from \"./useAdzenInlineAds.js\";\nexport {\n dispatchPlacementEvent,\n dispatchInlineAdEvent,\n dispatchPlacementEvents,\n} from \"./bridge.js\";\n","import { useRef, useEffect, useState } from \"react\";\nimport { observeViewability } from \"@adzenai/core\";\nimport { useAdzenPlacement } from \"./useAdzenPlacement.js\";\n\nexport interface AdzenCardProps {\n messageId: string;\n adUnitPosition?: string;\n viewabilityThresholdMs?: number;\n className?: string;\n}\n\nfunction fireBeacon(url: string): void {\n fetch(url, { method: \"GET\", keepalive: true }).catch(() => {\n setTimeout(() => {\n fetch(url, { method: \"GET\", keepalive: true }).catch(() => {});\n }, 1000);\n });\n}\n\n/**\n * Renders a sponsored ad card for a given assistant message. Returns `null`\n * (no DOM output) when there is no ad for the message.\n */\nexport function AdzenCard({\n messageId,\n adUnitPosition = \"chin\",\n viewabilityThresholdMs = 1000,\n className,\n}: AdzenCardProps) {\n const { getAdForMessage } = useAdzenPlacement();\n const ad = getAdForMessage(messageId);\n const cardRef = useRef<HTMLDivElement>(null);\n const [renderFired, setRenderFired] = useState(false);\n const [viewed, setViewed] = useState(false);\n\n useEffect(() => {\n if (!ad || renderFired || !ad.render_impression_url) return;\n setRenderFired(true);\n\n const url = new URL(ad.render_impression_url);\n url.searchParams.set(\"ad_unit_position\", adUnitPosition);\n url.searchParams.set(\"timestamp\", new Date().toISOString());\n fireBeacon(url.toString());\n }, [ad, renderFired, adUnitPosition]);\n\n useEffect(() => {\n if (!ad || !cardRef.current || viewed || !ad.view_impression_url) return;\n\n return observeViewability({\n element: cardRef.current,\n thresholdMs: viewabilityThresholdMs,\n onViewed: () => {\n setViewed(true);\n if (!ad.view_impression_url) return;\n const url = new URL(ad.view_impression_url);\n url.searchParams.set(\"ad_unit_position\", adUnitPosition);\n url.searchParams.set(\"viewability_ms\", String(viewabilityThresholdMs));\n url.searchParams.set(\"timestamp\", new Date().toISOString());\n fireBeacon(url.toString());\n },\n });\n }, [ad, viewed, adUnitPosition, viewabilityThresholdMs]);\n\n if (!ad) return null;\n\n const initial = ad.advertiser_name?.charAt(0).toUpperCase() ?? \"?\";\n\n return (\n <div\n ref={cardRef}\n className={className}\n data-adzen-ad-unit-position={adUnitPosition}\n style={cardStyles.wrapper}\n >\n <div style={cardStyles.avatar}>\n {ad.advertiser_image_url ? (\n <img\n src={ad.advertiser_image_url}\n alt={ad.advertiser_name}\n style={cardStyles.avatarImg}\n />\n ) : (\n <span style={cardStyles.avatarLetter}>{initial}</span>\n )}\n </div>\n\n <div style={cardStyles.content}>\n <div style={cardStyles.topRow}>\n <span style={cardStyles.advertiserName}>{ad.advertiser_name}</span>\n <span style={cardStyles.relevantAd}>Relevant Ad</span>\n </div>\n <div style={cardStyles.bottomRow}>\n <span style={cardStyles.headline}>{ad.headline}</span>\n <a\n href={ad.destination_url}\n target=\"_blank\"\n rel=\"noopener sponsored\"\n style={cardStyles.cta}\n >\n {ad.cta_text}\n </a>\n </div>\n </div>\n </div>\n );\n}\n\nconst cardStyles: Record<string, React.CSSProperties> = {\n wrapper: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.625rem\",\n fontSize: \"0.85rem\",\n padding: \"0.625rem 0.75rem\",\n },\n avatar: {\n width: 32,\n height: 32,\n borderRadius: \"50%\",\n background: \"#d1d5db\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n overflow: \"hidden\",\n },\n avatarImg: {\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\" as const,\n borderRadius: \"50%\",\n },\n avatarLetter: {\n fontSize: \"0.8rem\",\n fontWeight: 700,\n color: \"#374151\",\n lineHeight: 1,\n },\n content: {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"0.125rem\",\n minWidth: 0,\n },\n topRow: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n },\n advertiserName: {\n fontWeight: 700,\n color: \"inherit\",\n },\n relevantAd: {\n color: \"#8b949e\",\n fontSize: \"0.8rem\",\n },\n bottomRow: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n whiteSpace: \"nowrap\" as const,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n },\n headline: {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n },\n cta: {\n color: \"#58a6ff\",\n textDecoration: \"none\",\n fontWeight: 500,\n flexShrink: 0,\n },\n};\n","import { useState, useEffect, useCallback } from \"react\";\nimport type { AdzenPlacement } from \"@adzenai/core\";\n\nexport interface UseAdzenPlacementReturn {\n getAdForMessage(messageId: string): AdzenPlacement | null;\n placements: Map<string, AdzenPlacement>;\n}\n\n/**\n * React hook that subscribes to `adzen_placement` custom events and\n * maintains a map of messageId -> AdzenPlacement.\n *\n * Works anywhere in the React tree below `<CopilotKit>` — no wrapper\n * provider required.\n */\nexport function useAdzenPlacement(): UseAdzenPlacementReturn {\n const [placements, setPlacements] = useState<Map<string, AdzenPlacement>>(\n () => new Map(),\n );\n\n useEffect(() => {\n function handler(e: Event) {\n const detail = (e as CustomEvent).detail;\n if (!detail || typeof detail !== \"object\") return;\n\n const placement = detail as AdzenPlacement & { message_id?: string };\n const messageId = placement.message_id;\n if (!messageId) return;\n\n setPlacements((prev) => {\n const existing = prev.get(messageId);\n if (existing && existing.ad_id === placement.ad_id) return prev;\n const next = new Map(prev);\n next.set(messageId, placement);\n return next;\n });\n }\n\n window.addEventListener(\"adzen_placement\", handler);\n return () => window.removeEventListener(\"adzen_placement\", handler);\n }, []);\n\n const getAdForMessage = useCallback(\n (messageId: string): AdzenPlacement | null => {\n return placements.get(messageId) ?? null;\n },\n [placements],\n );\n\n return { getAdForMessage, placements };\n}\n","import { useRef, useEffect, useState } from \"react\";\nimport { observeViewability } from \"@adzenai/core\";\nimport type { InlineAdEvent } from \"@adzenai/core\";\n\nexport interface InlineAdProps {\n ad: InlineAdEvent;\n viewabilityThresholdMs?: number;\n className?: string;\n}\n\nfunction fireBeacon(url: string): void {\n fetch(url, { method: \"GET\", keepalive: true }).catch(() => {\n setTimeout(() => {\n fetch(url, { method: \"GET\", keepalive: true }).catch(() => {});\n }, 1000);\n });\n}\n\n/**\n * Renders an inline ad as a single line of text — an \"Ad\" pill, the advertiser\n * name, and the CTA as the only link — rather than a card, so it sits in the\n * message body without competing with the assistant's own content.\n *\n * Tracks render/view impressions via the same beacon pattern as AdzenCard.\n */\nexport function InlineAd({\n ad,\n viewabilityThresholdMs = 1000,\n className,\n}: InlineAdProps) {\n const ref = useRef<HTMLDivElement>(null);\n const [renderFired, setRenderFired] = useState(false);\n const [viewed, setViewed] = useState(false);\n\n useEffect(() => {\n if (renderFired || !ad.tracking.impression_url) return;\n setRenderFired(true);\n\n const url = new URL(ad.tracking.impression_url);\n url.searchParams.set(\"timestamp\", new Date().toISOString());\n fireBeacon(url.toString());\n }, [ad, renderFired]);\n\n useEffect(() => {\n if (!ref.current || viewed || !ad.tracking.impression_url) return;\n\n return observeViewability({\n element: ref.current,\n thresholdMs: viewabilityThresholdMs,\n onViewed: () => {\n setViewed(true);\n if (!ad.tracking.impression_url) return;\n const url = new URL(ad.tracking.impression_url);\n url.searchParams.set(\"type\", \"view\");\n url.searchParams.set(\"viewability_ms\", String(viewabilityThresholdMs));\n url.searchParams.set(\"timestamp\", new Date().toISOString());\n fireBeacon(url.toString());\n },\n });\n }, [ad, viewed, viewabilityThresholdMs]);\n\n const advertiser = ad.creative.advertiser_name ?? ad.creative.headline;\n\n return (\n <div ref={ref} className={className} style={inlineStyles.wrapper}>\n <span style={inlineStyles.badge} aria-label=\"Advertisement\">\n Ad\n </span>\n {advertiser ? (\n <span style={inlineStyles.advertiser}>{advertiser} </span>\n ) : null}\n <a\n href={ad.creative.destination_url}\n target=\"_blank\"\n rel=\"noopener sponsored\"\n style={inlineStyles.cta}\n >\n {ad.creative.cta_text}\n </a>\n </div>\n );\n}\n\nconst inlineStyles: Record<string, React.CSSProperties> = {\n // Block-level so the snippet starts on its own line below the text it\n // follows, but otherwise plain: no border, background, or padding.\n wrapper: {\n display: \"block\",\n margin: \"0.5rem 0\",\n fontSize: \"0.9em\",\n lineHeight: 1.5,\n },\n badge: {\n display: \"inline-block\",\n marginRight: \"0.4em\",\n padding: \"0.1em 0.4em\",\n borderRadius: 4,\n background: \"#30363d\",\n color: \"#8b949e\",\n fontSize: \"0.75em\",\n fontWeight: 700,\n letterSpacing: \"0.05em\",\n textTransform: \"uppercase\" as const,\n verticalAlign: \"middle\",\n },\n advertiser: {\n color: \"#8b949e\",\n },\n cta: {\n color: \"#58a6ff\",\n textDecoration: \"none\",\n fontWeight: 500,\n },\n};\n","import { useState, useEffect, useCallback } from \"react\";\nimport type { InlineAdEvent, InlineAdEventPayload } from \"@adzenai/core\";\n\n/** A run of message text, or an ad anchored to the end of the run before it. */\nexport type InlineAdSegment =\n | { kind: \"text\"; text: string }\n | { kind: \"ad\"; ad: InlineAdEventPayload };\n\nexport interface UseAdzenInlineAdsReturn {\n getInlineAdsForMessage(messageId: string): InlineAdEventPayload[];\n getInlineAdSegments(messageId: string, content: string): InlineAdSegment[];\n}\n\n/**\n * Ads without an anchor sort last so they render at the end of the message,\n * which is the best guess for a payload that predates `content_offset`.\n */\nfunction readOffset(payload: InlineAdEvent & { content_offset?: unknown }): number {\n return typeof payload.content_offset === \"number\"\n ? payload.content_offset\n : Number.MAX_SAFE_INTEGER;\n}\n\n/** A blank line, which ends a paragraph in both plain text and Markdown. */\nconst PARAGRAPH_BREAK = /\\n[ \\t]*\\n/;\nconst ENDS_ON_PARAGRAPH_BREAK = /\\n[ \\t]*\\n$/;\n\n/**\n * Moves an anchor forward to the end of the paragraph it falls in.\n *\n * Deltas are token-sized, so a raw offset routinely lands mid-word or inside\n * a Markdown construct (`**bold te|xt**`). Splitting there would break both\n * the sentence and the Markdown, so the ad is deferred to the next paragraph\n * break — the `paragraph_break` position the API asks for. While the paragraph\n * is still streaming there is no break yet, so the ad sits at the end of the\n * content and settles into place once the paragraph closes.\n */\nfunction snapToParagraphEnd(content: string, offset: number): number {\n if (offset >= content.length) return content.length;\n\n // The preceding frame already ended on a blank line, so this is the start of\n // a fresh paragraph and the ad belongs here.\n if (ENDS_ON_PARAGRAPH_BREAK.test(content.slice(0, offset))) return offset;\n\n // Search from one character back so an offset landing inside the blank line\n // itself still resolves to that break rather than skipping to the next one.\n return nextParagraphEnd(content, Math.max(0, offset - 1));\n}\n\n/**\n * Position just past the first paragraph break at or after `from`, or the end\n * of the content when no break follows.\n */\nfunction nextParagraphEnd(content: string, from: number): number {\n if (from >= content.length) return content.length;\n const match = PARAGRAPH_BREAK.exec(content.slice(from));\n return match ? from + match.index + match[0].length : content.length;\n}\n\n/**\n * Splits `content` into text and ad segments, placing each ad after the text\n * that had streamed when it arrived.\n *\n * At most one ad is placed per paragraph break. Several ads routinely resolve\n * to the same break — the API can emit a burst of them, and every ad anchored\n * inside one paragraph snaps to that paragraph's end — so each ad after the\n * first is moved to the next free break, with the end of the content usable as\n * a final slot. An ad with no free slot is left out and appears once the\n * message has grown enough to hold it, which keeps ads from piling up in one\n * spot while a paragraph is still streaming.\n *\n * @param ads Must be sorted by `content_offset` ascending.\n */\nexport function buildInlineAdSegments(\n content: string,\n ads: InlineAdEventPayload[],\n): InlineAdSegment[] {\n if (ads.length === 0) {\n return content ? [{ kind: \"text\", text: content }] : [];\n }\n\n const segments: InlineAdSegment[] = [];\n let cursor = 0;\n let lastAnchor = -1;\n\n for (const ad of ads) {\n let anchor = snapToParagraphEnd(content, Math.max(ad.content_offset, 0));\n if (anchor <= lastAnchor) anchor = nextParagraphEnd(content, lastAnchor);\n if (anchor <= lastAnchor) continue;\n\n if (anchor > cursor) {\n segments.push({ kind: \"text\", text: content.slice(cursor, anchor) });\n }\n segments.push({ kind: \"ad\", ad });\n cursor = anchor;\n lastAnchor = anchor;\n }\n\n if (cursor < content.length) {\n segments.push({ kind: \"text\", text: content.slice(cursor) });\n }\n\n return segments;\n}\n\n/**\n * React hook that subscribes to `adzen_inline_ad` custom events on\n * `window` and maintains a map of messageId -> InlineAdEventPayload[].\n *\n * Supports multiple inline ads per message per the cardinality requirements.\n * Ads are kept sorted by `content_offset` so they can be interleaved with the\n * message text at the point in the stream where they arrived.\n */\nexport function useAdzenInlineAds(): UseAdzenInlineAdsReturn {\n const [adsMap, setAdsMap] = useState<Map<string, InlineAdEventPayload[]>>(\n () => new Map(),\n );\n\n useEffect(() => {\n function handler(e: Event) {\n const detail = (e as CustomEvent).detail;\n if (!detail || typeof detail !== \"object\") return;\n\n const payload = detail as InlineAdEvent & { message_id?: string };\n const messageId = payload.message_id;\n if (!messageId) return;\n\n const anchored: InlineAdEventPayload = {\n ...payload,\n message_id: messageId,\n content_offset: readOffset(payload),\n };\n\n setAdsMap((prev) => {\n const existing = prev.get(messageId) ?? [];\n if (existing.some((a) => a.ad_id === anchored.ad_id)) return prev;\n const next = new Map(prev);\n next.set(\n messageId,\n [...existing, anchored].sort(\n (a, b) => a.content_offset - b.content_offset,\n ),\n );\n return next;\n });\n }\n\n window.addEventListener(\"adzen_inline_ad\", handler);\n return () => window.removeEventListener(\"adzen_inline_ad\", handler);\n }, []);\n\n const getInlineAdsForMessage = useCallback(\n (messageId: string): InlineAdEventPayload[] => {\n return adsMap.get(messageId) ?? [];\n },\n [adsMap],\n );\n\n const getInlineAdSegments = useCallback(\n (messageId: string, content: string): InlineAdSegment[] =>\n buildInlineAdSegments(content, adsMap.get(messageId) ?? []),\n [adsMap],\n );\n\n return { getInlineAdsForMessage, getInlineAdSegments };\n}\n","import type { AdzenPlacement, InlineAdEventPayload } from \"@adzenai/core\";\n\nfunction isCustomEvent(event: Record<string, unknown>): boolean {\n const type = String(event.type ?? \"\");\n return type === \"CUSTOM_EVENT\" || type === \"CUSTOM\" || type === \"CustomEvent\";\n}\n\n/**\n * Checks whether an AG-UI event is an `adzen_placement` custom event\n * and, if so, dispatches it as a browser `CustomEvent` on `window`\n * so that `useAdzenPlacement` can pick it up.\n *\n * Call this for every event returned by middleware `processEvent()` or\n * `processStream()`. Non-placement events are silently ignored.\n */\nexport function dispatchPlacementEvent(\n event: Record<string, unknown>,\n): boolean {\n if (typeof window === \"undefined\") return false;\n if (event.name !== \"adzen_placement\") return false;\n if (!isCustomEvent(event)) return false;\n\n const value = event.value as (AdzenPlacement & { message_id?: string }) | undefined;\n if (!value) return false;\n\n window.dispatchEvent(\n new CustomEvent(\"adzen_placement\", { detail: value }),\n );\n return true;\n}\n\n/**\n * Checks whether an AG-UI event is an `adzen_inline_ad` custom event\n * and, if so, dispatches it as a browser `CustomEvent` on `window`\n * so that `useAdzenInlineAds` can pick it up.\n */\nexport function dispatchInlineAdEvent(\n event: Record<string, unknown>,\n): boolean {\n if (typeof window === \"undefined\") return false;\n if (event.name !== \"adzen_inline_ad\") return false;\n if (!isCustomEvent(event)) return false;\n\n const value = event.value as Partial<InlineAdEventPayload> | undefined;\n if (!value) return false;\n\n window.dispatchEvent(\n new CustomEvent(\"adzen_inline_ad\", { detail: value }),\n );\n return true;\n}\n\n/**\n * Convenience wrapper: iterates an array of AG-UI events and dispatches\n * any placement or inline ad events to the browser.\n */\nexport function dispatchPlacementEvents(\n events: Record<string, unknown>[],\n): void {\n for (const event of events) {\n dispatchPlacementEvent(event);\n dispatchInlineAdEvent(event);\n }\n}\n"],"mappings":"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","names":["import_react","import_react","import_core","import_jsx_runtime","fireBeacon","import_react"]}
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { AdzenPlacement } from '@adzenai/core';
2
+ import { InlineAdEvent, AdzenPlacement, InlineAdEventPayload } from '@adzenai/core';
3
3
 
4
4
  interface AdzenCardProps {
5
5
  messageId: string;
@@ -13,6 +13,20 @@ interface AdzenCardProps {
13
13
  */
14
14
  declare function AdzenCard({ messageId, adUnitPosition, viewabilityThresholdMs, className, }: AdzenCardProps): react.JSX.Element | null;
15
15
 
16
+ interface InlineAdProps {
17
+ ad: InlineAdEvent;
18
+ viewabilityThresholdMs?: number;
19
+ className?: string;
20
+ }
21
+ /**
22
+ * Renders an inline ad as a single line of text — an "Ad" pill, the advertiser
23
+ * name, and the CTA as the only link — rather than a card, so it sits in the
24
+ * message body without competing with the assistant's own content.
25
+ *
26
+ * Tracks render/view impressions via the same beacon pattern as AdzenCard.
27
+ */
28
+ declare function InlineAd({ ad, viewabilityThresholdMs, className, }: InlineAdProps): react.JSX.Element;
29
+
16
30
  interface UseAdzenPlacementReturn {
17
31
  getAdForMessage(messageId: string): AdzenPlacement | null;
18
32
  placements: Map<string, AdzenPlacement>;
@@ -26,20 +40,62 @@ interface UseAdzenPlacementReturn {
26
40
  */
27
41
  declare function useAdzenPlacement(): UseAdzenPlacementReturn;
28
42
 
43
+ /** A run of message text, or an ad anchored to the end of the run before it. */
44
+ type InlineAdSegment = {
45
+ kind: "text";
46
+ text: string;
47
+ } | {
48
+ kind: "ad";
49
+ ad: InlineAdEventPayload;
50
+ };
51
+ interface UseAdzenInlineAdsReturn {
52
+ getInlineAdsForMessage(messageId: string): InlineAdEventPayload[];
53
+ getInlineAdSegments(messageId: string, content: string): InlineAdSegment[];
54
+ }
55
+ /**
56
+ * Splits `content` into text and ad segments, placing each ad after the text
57
+ * that had streamed when it arrived.
58
+ *
59
+ * At most one ad is placed per paragraph break. Several ads routinely resolve
60
+ * to the same break — the API can emit a burst of them, and every ad anchored
61
+ * inside one paragraph snaps to that paragraph's end — so each ad after the
62
+ * first is moved to the next free break, with the end of the content usable as
63
+ * a final slot. An ad with no free slot is left out and appears once the
64
+ * message has grown enough to hold it, which keeps ads from piling up in one
65
+ * spot while a paragraph is still streaming.
66
+ *
67
+ * @param ads Must be sorted by `content_offset` ascending.
68
+ */
69
+ declare function buildInlineAdSegments(content: string, ads: InlineAdEventPayload[]): InlineAdSegment[];
70
+ /**
71
+ * React hook that subscribes to `adzen_inline_ad` custom events on
72
+ * `window` and maintains a map of messageId -> InlineAdEventPayload[].
73
+ *
74
+ * Supports multiple inline ads per message per the cardinality requirements.
75
+ * Ads are kept sorted by `content_offset` so they can be interleaved with the
76
+ * message text at the point in the stream where they arrived.
77
+ */
78
+ declare function useAdzenInlineAds(): UseAdzenInlineAdsReturn;
79
+
29
80
  /**
30
81
  * Checks whether an AG-UI event is an `adzen_placement` custom event
31
82
  * and, if so, dispatches it as a browser `CustomEvent` on `window`
32
83
  * so that `useAdzenPlacement` can pick it up.
33
84
  *
34
- * Call this for every event returned by `AdzenAsyncMiddleware.processEvent()`.
35
- * Non-placement events are silently ignored.
85
+ * Call this for every event returned by middleware `processEvent()` or
86
+ * `processStream()`. Non-placement events are silently ignored.
36
87
  */
37
88
  declare function dispatchPlacementEvent(event: Record<string, unknown>): boolean;
38
89
  /**
39
- * Convenience wrapper: iterates an array of AG-UI events (as returned by
40
- * `AdzenAsyncMiddleware.processEvent()`) and dispatches any placement
41
- * events to the browser.
90
+ * Checks whether an AG-UI event is an `adzen_inline_ad` custom event
91
+ * and, if so, dispatches it as a browser `CustomEvent` on `window`
92
+ * so that `useAdzenInlineAds` can pick it up.
93
+ */
94
+ declare function dispatchInlineAdEvent(event: Record<string, unknown>): boolean;
95
+ /**
96
+ * Convenience wrapper: iterates an array of AG-UI events and dispatches
97
+ * any placement or inline ad events to the browser.
42
98
  */
43
99
  declare function dispatchPlacementEvents(events: Record<string, unknown>[]): void;
44
100
 
45
- export { AdzenCard, type AdzenCardProps, type UseAdzenPlacementReturn, dispatchPlacementEvent, dispatchPlacementEvents, useAdzenPlacement };
101
+ export { AdzenCard, type AdzenCardProps, InlineAd, type InlineAdProps, type InlineAdSegment, type UseAdzenInlineAdsReturn, type UseAdzenPlacementReturn, buildInlineAdSegments, dispatchInlineAdEvent, dispatchPlacementEvent, dispatchPlacementEvents, useAdzenInlineAds, useAdzenPlacement };
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { AdzenPlacement } from '@adzenai/core';
2
+ import { InlineAdEvent, AdzenPlacement, InlineAdEventPayload } from '@adzenai/core';
3
3
 
4
4
  interface AdzenCardProps {
5
5
  messageId: string;
@@ -13,6 +13,20 @@ interface AdzenCardProps {
13
13
  */
14
14
  declare function AdzenCard({ messageId, adUnitPosition, viewabilityThresholdMs, className, }: AdzenCardProps): react.JSX.Element | null;
15
15
 
16
+ interface InlineAdProps {
17
+ ad: InlineAdEvent;
18
+ viewabilityThresholdMs?: number;
19
+ className?: string;
20
+ }
21
+ /**
22
+ * Renders an inline ad as a single line of text — an "Ad" pill, the advertiser
23
+ * name, and the CTA as the only link — rather than a card, so it sits in the
24
+ * message body without competing with the assistant's own content.
25
+ *
26
+ * Tracks render/view impressions via the same beacon pattern as AdzenCard.
27
+ */
28
+ declare function InlineAd({ ad, viewabilityThresholdMs, className, }: InlineAdProps): react.JSX.Element;
29
+
16
30
  interface UseAdzenPlacementReturn {
17
31
  getAdForMessage(messageId: string): AdzenPlacement | null;
18
32
  placements: Map<string, AdzenPlacement>;
@@ -26,20 +40,62 @@ interface UseAdzenPlacementReturn {
26
40
  */
27
41
  declare function useAdzenPlacement(): UseAdzenPlacementReturn;
28
42
 
43
+ /** A run of message text, or an ad anchored to the end of the run before it. */
44
+ type InlineAdSegment = {
45
+ kind: "text";
46
+ text: string;
47
+ } | {
48
+ kind: "ad";
49
+ ad: InlineAdEventPayload;
50
+ };
51
+ interface UseAdzenInlineAdsReturn {
52
+ getInlineAdsForMessage(messageId: string): InlineAdEventPayload[];
53
+ getInlineAdSegments(messageId: string, content: string): InlineAdSegment[];
54
+ }
55
+ /**
56
+ * Splits `content` into text and ad segments, placing each ad after the text
57
+ * that had streamed when it arrived.
58
+ *
59
+ * At most one ad is placed per paragraph break. Several ads routinely resolve
60
+ * to the same break — the API can emit a burst of them, and every ad anchored
61
+ * inside one paragraph snaps to that paragraph's end — so each ad after the
62
+ * first is moved to the next free break, with the end of the content usable as
63
+ * a final slot. An ad with no free slot is left out and appears once the
64
+ * message has grown enough to hold it, which keeps ads from piling up in one
65
+ * spot while a paragraph is still streaming.
66
+ *
67
+ * @param ads Must be sorted by `content_offset` ascending.
68
+ */
69
+ declare function buildInlineAdSegments(content: string, ads: InlineAdEventPayload[]): InlineAdSegment[];
70
+ /**
71
+ * React hook that subscribes to `adzen_inline_ad` custom events on
72
+ * `window` and maintains a map of messageId -> InlineAdEventPayload[].
73
+ *
74
+ * Supports multiple inline ads per message per the cardinality requirements.
75
+ * Ads are kept sorted by `content_offset` so they can be interleaved with the
76
+ * message text at the point in the stream where they arrived.
77
+ */
78
+ declare function useAdzenInlineAds(): UseAdzenInlineAdsReturn;
79
+
29
80
  /**
30
81
  * Checks whether an AG-UI event is an `adzen_placement` custom event
31
82
  * and, if so, dispatches it as a browser `CustomEvent` on `window`
32
83
  * so that `useAdzenPlacement` can pick it up.
33
84
  *
34
- * Call this for every event returned by `AdzenAsyncMiddleware.processEvent()`.
35
- * Non-placement events are silently ignored.
85
+ * Call this for every event returned by middleware `processEvent()` or
86
+ * `processStream()`. Non-placement events are silently ignored.
36
87
  */
37
88
  declare function dispatchPlacementEvent(event: Record<string, unknown>): boolean;
38
89
  /**
39
- * Convenience wrapper: iterates an array of AG-UI events (as returned by
40
- * `AdzenAsyncMiddleware.processEvent()`) and dispatches any placement
41
- * events to the browser.
90
+ * Checks whether an AG-UI event is an `adzen_inline_ad` custom event
91
+ * and, if so, dispatches it as a browser `CustomEvent` on `window`
92
+ * so that `useAdzenInlineAds` can pick it up.
93
+ */
94
+ declare function dispatchInlineAdEvent(event: Record<string, unknown>): boolean;
95
+ /**
96
+ * Convenience wrapper: iterates an array of AG-UI events and dispatches
97
+ * any placement or inline ad events to the browser.
42
98
  */
43
99
  declare function dispatchPlacementEvents(events: Record<string, unknown>[]): void;
44
100
 
45
- export { AdzenCard, type AdzenCardProps, type UseAdzenPlacementReturn, dispatchPlacementEvent, dispatchPlacementEvents, useAdzenPlacement };
101
+ export { AdzenCard, type AdzenCardProps, InlineAd, type InlineAdProps, type InlineAdSegment, type UseAdzenInlineAdsReturn, type UseAdzenPlacementReturn, buildInlineAdSegments, dispatchInlineAdEvent, dispatchPlacementEvent, dispatchPlacementEvents, useAdzenInlineAds, useAdzenPlacement };