@chativa/connector-directline 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { DirectLine as v, ConnectionStatus as l } from "botframework-directlinejs";
2
- const f = /* @__PURE__ */ Symbol("typing"), k = "application/vnd.microsoft.card.hero", b = "application/vnd.microsoft.card.thumbnail", p = "application/vnd.microsoft.card.adaptive", S = "application/vnd.microsoft.card.signin", H = "application/vnd.microsoft.card.oauth", A = "application/vnd.microsoft.card.receipt", D = "application/vnd.microsoft.card.audio", E = "application/vnd.microsoft.card.video", $ = "application/vnd.microsoft.card.animation", T = "application/vnd.microsoft.card.flex";
2
+ const f = /* @__PURE__ */ Symbol("typing"), k = "application/vnd.microsoft.card.hero", b = "application/vnd.microsoft.card.thumbnail", m = "application/vnd.microsoft.card.adaptive", S = "application/vnd.microsoft.card.signin", H = "application/vnd.microsoft.card.oauth", A = "application/vnd.microsoft.card.receipt", D = "application/vnd.microsoft.card.audio", E = "application/vnd.microsoft.card.video", $ = "application/vnd.microsoft.card.animation", T = "application/vnd.microsoft.card.flex";
3
3
  function y(i, t) {
4
4
  if (i.from.id === t) return null;
5
5
  if (i.type === "typing") return f;
6
6
  if (i.type !== "message") return null;
7
7
  const e = i, n = e.id ?? `dl-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, s = e.timestamp ? new Date(e.timestamp).getTime() : Date.now(), r = e.channelData, o = U(e);
8
8
  if (e.attachments && e.attachments.length > 0) {
9
- const a = L(e, n, s);
9
+ const a = N(e, n, s);
10
10
  return a && (o.length > 0 && (a.actions = o), r && (a.data.channelData = r)), a;
11
11
  }
12
12
  return o.length > 0 ? {
@@ -23,21 +23,21 @@ function y(i, t) {
23
23
  timestamp: s
24
24
  } : null;
25
25
  }
26
- function L(i, t, e) {
27
- const n = i.attachments, s = i.attachmentLayout, r = [k, b, T, p];
26
+ function N(i, t, e) {
27
+ const n = i.attachments, s = i.attachmentLayout, r = [k, b, T, m];
28
28
  return n.every((a) => r.includes(a.contentType)) && (n.length > 1 || s === "carousel") ? {
29
29
  id: t,
30
30
  type: "carousel",
31
31
  from: "bot",
32
32
  data: {
33
- cards: n.map((a) => a.contentType === p ? R(
33
+ cards: n.map((a) => a.contentType === m ? R(
34
34
  a.content
35
35
  ) : I(a.content))
36
36
  },
37
37
  timestamp: e
38
- } : N(n[0], i, t, e);
38
+ } : L(n[0], i, t, e);
39
39
  }
40
- function N(i, t, e, n) {
40
+ function L(i, t, e, n) {
41
41
  const s = i.contentType;
42
42
  if (s === k || s === b || s === T) {
43
43
  const r = i.content;
@@ -49,7 +49,7 @@ function N(i, t, e, n) {
49
49
  timestamp: n
50
50
  };
51
51
  }
52
- if (s === p)
52
+ if (s === m)
53
53
  return _(i.content, e, n);
54
54
  if (s === S || s === H) {
55
55
  const r = i.content;
@@ -59,7 +59,7 @@ function N(i, t, e, n) {
59
59
  from: "bot",
60
60
  data: {
61
61
  text: r.text ?? "Please sign in",
62
- buttons: C(r.buttons)
62
+ buttons: w(r.buttons)
63
63
  },
64
64
  timestamp: n
65
65
  };
@@ -143,10 +143,10 @@ function I(i) {
143
143
  image: i.images?.[0]?.url,
144
144
  title: i.title ?? "",
145
145
  subtitle: i.subtitle ?? i.text,
146
- buttons: C(i.buttons)
146
+ buttons: w(i.buttons)
147
147
  };
148
148
  }
149
- function C(i) {
149
+ function w(i) {
150
150
  return !i || i.length === 0 ? [] : i.map((t) => {
151
151
  const e = ("title" in t ? t.title : void 0) ?? String(t.value ?? "");
152
152
  switch (t.type) {
@@ -192,7 +192,7 @@ function d(i, t, e, n) {
192
192
  break;
193
193
  }
194
194
  }
195
- function w(i) {
195
+ function C(i) {
196
196
  const t = [];
197
197
  let e;
198
198
  const n = [];
@@ -206,7 +206,7 @@ function w(i) {
206
206
  ), Array.isArray(i.actions) && x(i.actions, n), { texts: t, image: e, buttons: n };
207
207
  }
208
208
  function R(i) {
209
- const { texts: t, image: e, buttons: n } = w(i);
209
+ const { texts: t, image: e, buttons: n } = C(i);
210
210
  return {
211
211
  image: e,
212
212
  title: t[0] ?? "",
@@ -216,7 +216,7 @@ function R(i) {
216
216
  };
217
217
  }
218
218
  function _(i, t, e) {
219
- const { texts: n, image: s, buttons: r } = w(i), o = i.fallbackText ?? i.speak ?? n.join(`
219
+ const { texts: n, image: s, buttons: r } = C(i), o = i.fallbackText ?? i.speak ?? n.join(`
220
220
  `);
221
221
  return s ? {
222
222
  id: t,
@@ -294,7 +294,7 @@ function B(i) {
294
294
  return null;
295
295
  }
296
296
  }
297
- async function j(i, t) {
297
+ async function F(i, t) {
298
298
  const e = await fetch(
299
299
  "https://directline.botframework.com/v3/directline/tokens/generate",
300
300
  {
@@ -311,7 +311,7 @@ async function j(i, t) {
311
311
  const n = await e.json();
312
312
  return { token: n.token, conversationId: n.conversationId };
313
313
  }
314
- async function F(i) {
314
+ async function j(i) {
315
315
  const t = await fetch(i, { method: "POST" });
316
316
  if (!t.ok)
317
317
  throw new Error(`Token generator failed: ${t.status}`);
@@ -379,14 +379,14 @@ class J {
379
379
  }
380
380
  if (!t)
381
381
  if (this.options.tokenGeneratorUrl) {
382
- const n = await F(
382
+ const n = await j(
383
383
  this.options.tokenGeneratorUrl
384
384
  );
385
385
  this.token = n.token, n.conversationId && (this.conversationId = n.conversationId), n.userId && (this.userId = n.userId);
386
386
  } else if (this.options.token)
387
387
  this.token = this.options.token;
388
388
  else if (this.options.secret) {
389
- const n = await j(
389
+ const n = await F(
390
390
  this.options.secret,
391
391
  this.userId
392
392
  );
@@ -451,6 +451,32 @@ class J {
451
451
  if (!r.ok)
452
452
  throw new Error(`DirectLine file upload failed: ${r.status}`);
453
453
  }
454
+ /**
455
+ * Submit an end-of-conversation survey as a DirectLine event activity.
456
+ * Matches the legacy `webchat/customerfeedback` event shape so existing
457
+ * bot flows keep working:
458
+ * value: { rating, comment, type }
459
+ * where `type` is `kind` coerced to a number (defaulting to 1) to preserve
460
+ * compatibility with bots that switch on numeric survey types.
461
+ */
462
+ async sendSurvey(t) {
463
+ const e = typeof t.kind == "number" ? t.kind : t.kind !== void 0 ? Number(t.kind) : 1, n = Number.isFinite(e) ? e : 1;
464
+ return new Promise((s, r) => {
465
+ this.directLine.postActivity({
466
+ type: "event",
467
+ name: "webchat/customerfeedback",
468
+ from: { id: this.userId, name: this.userId },
469
+ value: {
470
+ rating: t.rating,
471
+ comment: t.comment ?? "",
472
+ type: n
473
+ }
474
+ }).subscribe({
475
+ next: () => s(),
476
+ error: (o) => r(o)
477
+ });
478
+ });
479
+ }
454
480
  async sendFeedback(t, e) {
455
481
  const s = this.chativaCtx?.messages.getAll().find((o) => o.id === t)?.data?.channelData?.correlationId;
456
482
  if (!s) {
@@ -482,12 +508,12 @@ class J {
482
508
  const r = await s.json(), o = [];
483
509
  for (const a of r.activities) {
484
510
  if (a.from.id === this.userId && a.type === "message") {
485
- const m = a;
486
- m.text && o.push({
511
+ const p = a;
512
+ p.text && o.push({
487
513
  id: a.id ?? `dl-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
488
514
  type: "text",
489
515
  from: "user",
490
- data: { text: m.text },
516
+ data: { text: p.text },
491
517
  timestamp: a.timestamp ? new Date(a.timestamp).getTime() : Date.now()
492
518
  });
493
519
  continue;
@@ -596,7 +622,7 @@ class J {
596
622
  /** Send webchat/join (first connect) or webchat/rejoin (reconnect) event. */
597
623
  sendJoinEvent() {
598
624
  const t = this.options.locale, e = { id: this.userId, name: this.userName ?? this.userId };
599
- if (this._skipNextJoin) {
625
+ if (this.hasConnectedBefore, this._skipNextJoin) {
600
626
  this._skipNextJoin = !1, this.hasConnectedBefore = !0, this.directLine.postActivity({
601
627
  type: "event",
602
628
  name: "webchat/rejoin",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/mapActivity.ts","../src/DirectLineConnector.ts"],"sourcesContent":["/**\n * Pure mapping functions that convert DirectLine activities\n * into Chativa IncomingMessage structures.\n *\n * No side-effects — all functions are stateless and easily testable.\n */\n\nimport type {\n Activity,\n Message,\n CardAction,\n Attachment,\n HeroCard,\n Thumbnail,\n Signin,\n Receipt,\n AudioCard,\n VideoCard,\n AnimationCard,\n AdaptiveCard,\n FlexCard,\n} from \"botframework-directlinejs\";\nimport type { IncomingMessage, MessageAction } from \"@chativa/core\";\n\n/* ------------------------------------------------------------------ */\n/* Sentinel returned for typing activities */\n/* ------------------------------------------------------------------ */\n\nexport const TYPING_SENTINEL = Symbol(\"typing\");\nexport type MapResult = IncomingMessage | typeof TYPING_SENTINEL | null;\n\n/* ------------------------------------------------------------------ */\n/* Content-type constants */\n/* ------------------------------------------------------------------ */\n\nconst CT_HERO = \"application/vnd.microsoft.card.hero\";\nconst CT_THUMBNAIL = \"application/vnd.microsoft.card.thumbnail\";\nconst CT_ADAPTIVE = \"application/vnd.microsoft.card.adaptive\";\nconst CT_SIGNIN = \"application/vnd.microsoft.card.signin\";\nconst CT_OAUTH = \"application/vnd.microsoft.card.oauth\";\nconst CT_RECEIPT = \"application/vnd.microsoft.card.receipt\";\nconst CT_AUDIO = \"application/vnd.microsoft.card.audio\";\nconst CT_VIDEO = \"application/vnd.microsoft.card.video\";\nconst CT_ANIMATION = \"application/vnd.microsoft.card.animation\";\nconst CT_FLEX = \"application/vnd.microsoft.card.flex\";\n\n/* ------------------------------------------------------------------ */\n/* Main entry point */\n/* ------------------------------------------------------------------ */\n\n/**\n * Convert a DirectLine Activity into a Chativa IncomingMessage.\n *\n * Returns:\n * - `IncomingMessage` for renderable messages\n * - `TYPING_SENTINEL` for typing indicators (handled by the connector)\n * - `null` for activities that should be ignored (echo, events, etc.)\n */\nexport function mapActivityToMessage(\n activity: Activity,\n userId: string,\n): MapResult {\n // Filter out echoed user messages\n if (activity.from.id === userId) return null;\n\n // Typing indicator\n if (activity.type === \"typing\") return TYPING_SENTINEL;\n\n // Only process message activities\n if (activity.type !== \"message\") return null;\n\n const msg = activity as Message;\n const id = msg.id ?? `dl-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n const timestamp = msg.timestamp ? new Date(msg.timestamp).getTime() : Date.now();\n\n // Preserve channelData (e.g. correlationId used for feedback)\n const channelData = (msg as unknown as { channelData?: Record<string, unknown> }).channelData;\n\n // Map suggested actions (may be used as top-level actions or as quick-reply)\n const suggestedActions = mapSuggestedActions(msg);\n\n // If there are attachments, process them\n if (msg.attachments && msg.attachments.length > 0) {\n const result = mapAttachments(msg, id, timestamp);\n if (result) {\n if (suggestedActions.length > 0) result.actions = suggestedActions;\n if (channelData) result.data.channelData = channelData;\n }\n return result;\n }\n\n // Text + suggested actions → quick-reply\n if (suggestedActions.length > 0) {\n return {\n id,\n type: \"quick-reply\",\n from: \"bot\",\n data: { text: msg.text ?? \"\", actions: suggestedActions, ...(channelData ? { channelData } : {}) },\n timestamp,\n };\n }\n\n // Plain text\n if (msg.text) {\n return {\n id,\n type: \"text\",\n from: \"bot\",\n data: { text: msg.text, ...(channelData ? { channelData } : {}) },\n timestamp,\n };\n }\n\n // Nothing meaningful\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Attachment mapping */\n/* ------------------------------------------------------------------ */\n\nfunction mapAttachments(\n msg: Message,\n id: string,\n timestamp: number,\n): IncomingMessage | null {\n const attachments = msg.attachments!;\n const layout = msg.attachmentLayout;\n\n // Multiple cards with carousel layout\n const cardTypes = [CT_HERO, CT_THUMBNAIL, CT_FLEX, CT_ADAPTIVE];\n const allCards = attachments.every((a) => cardTypes.includes(a.contentType));\n\n if (allCards && (attachments.length > 1 || layout === \"carousel\")) {\n return {\n id,\n type: \"carousel\",\n from: \"bot\",\n data: {\n cards: attachments.map((a) => {\n if (a.contentType === CT_ADAPTIVE) {\n return adaptiveCardToCardData(\n (a as AdaptiveCard).content as Record<string, unknown>,\n );\n }\n return mapHeroLikeCard((a as HeroCard | Thumbnail | FlexCard).content);\n }),\n },\n timestamp,\n };\n }\n\n // Single attachment\n return mapSingleAttachment(attachments[0], msg, id, timestamp);\n}\n\nfunction mapSingleAttachment(\n att: Attachment,\n msg: Message,\n id: string,\n timestamp: number,\n): IncomingMessage | null {\n const ct = att.contentType;\n\n // Hero / Thumbnail / Flex card\n if (ct === CT_HERO || ct === CT_THUMBNAIL || ct === CT_FLEX) {\n const content = (att as HeroCard | Thumbnail | FlexCard).content;\n return {\n id,\n type: \"card\",\n from: \"bot\",\n data: mapHeroLikeCard(content),\n timestamp,\n };\n }\n\n // Adaptive card — simple parse\n if (ct === CT_ADAPTIVE) {\n return mapAdaptiveCard((att as AdaptiveCard).content, id, timestamp);\n }\n\n // Signin / OAuth card\n if (ct === CT_SIGNIN || ct === CT_OAUTH) {\n const content = (att as Signin).content;\n return {\n id,\n type: \"buttons\",\n from: \"bot\",\n data: {\n text: content.text ?? \"Please sign in\",\n buttons: mapCardButtons(content.buttons),\n },\n timestamp,\n };\n }\n\n // Receipt card\n if (ct === CT_RECEIPT) {\n return mapReceiptCard((att as Receipt).content, id, timestamp);\n }\n\n // Video card\n if (ct === CT_VIDEO) {\n const content = (att as VideoCard).content;\n const mediaUrl = content.media?.[0]?.url;\n if (!mediaUrl) return null;\n return {\n id,\n type: \"video\",\n from: \"bot\",\n data: {\n src: mediaUrl,\n poster: content.image?.url,\n caption: content.title ?? msg.text,\n },\n timestamp,\n };\n }\n\n // Audio card\n if (ct === CT_AUDIO) {\n const content = (att as AudioCard).content;\n const mediaUrl = content.media?.[0]?.url;\n if (!mediaUrl) return null;\n return {\n id,\n type: \"file\",\n from: \"bot\",\n data: {\n url: mediaUrl,\n name: content.title ?? \"audio\",\n mimeType: \"audio/mpeg\",\n },\n timestamp,\n };\n }\n\n // Animation card (typically GIFs)\n if (ct === CT_ANIMATION) {\n const content = (att as AnimationCard).content;\n const mediaUrl = content.media?.[0]?.url;\n if (!mediaUrl) return null;\n return {\n id,\n type: \"image\",\n from: \"bot\",\n data: {\n src: mediaUrl,\n caption: content.title ?? msg.text,\n },\n timestamp,\n };\n }\n\n // Image attachment (contentType starts with \"image/\")\n if (ct.startsWith(\"image/\") && \"contentUrl\" in att) {\n return {\n id,\n type: \"image\",\n from: \"bot\",\n data: {\n src: att.contentUrl,\n alt: att.name,\n caption: msg.text,\n },\n timestamp,\n };\n }\n\n // Video file attachment\n if (ct.startsWith(\"video/\") && \"contentUrl\" in att) {\n return {\n id,\n type: \"video\",\n from: \"bot\",\n data: {\n src: att.contentUrl,\n caption: msg.text,\n },\n timestamp,\n };\n }\n\n // Generic file attachment\n if (\"contentUrl\" in att) {\n return {\n id,\n type: \"file\",\n from: \"bot\",\n data: {\n url: att.contentUrl,\n name: att.name ?? \"file\",\n mimeType: ct,\n },\n timestamp,\n };\n }\n\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Hero-like card mapping (hero, thumbnail, flex share same shape) */\n/* ------------------------------------------------------------------ */\n\nfunction mapHeroLikeCard(content: HeroCard[\"content\"]): Record<string, unknown> {\n return {\n image: content.images?.[0]?.url,\n title: content.title ?? \"\",\n subtitle: content.subtitle ?? content.text,\n buttons: mapCardButtons(content.buttons),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Card button / action mapping */\n/* ------------------------------------------------------------------ */\n\nexport function mapCardButtons(\n buttons?: CardAction[],\n): MessageAction[] {\n if (!buttons || buttons.length === 0) return [];\n\n return buttons.map((btn): MessageAction => {\n const label = (\"title\" in btn ? btn.title : undefined) ?? String(btn.value ?? \"\");\n\n switch (btn.type) {\n case \"openUrl\":\n case \"signin\":\n return { label, url: String(btn.value ?? \"\") };\n\n case \"call\":\n return { label, url: String(btn.value ?? \"\") };\n\n case \"imBack\":\n case \"postBack\":\n case \"messageBack\":\n default:\n return { label, value: String(btn.value ?? label) };\n }\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Suggested actions mapping */\n/* ------------------------------------------------------------------ */\n\nfunction mapSuggestedActions(msg: Message): MessageAction[] {\n const actions = msg.suggestedActions?.actions;\n if (!actions || actions.length === 0) return [];\n\n return actions.map((a): MessageAction => {\n const label = (\"title\" in a ? a.title : undefined) ?? String(a.value ?? \"\");\n if (a.type === \"openUrl\") {\n return { label, url: String(a.value ?? \"\") };\n }\n return { label, value: String(a.value ?? label) };\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Adaptive Card — simple parse */\n/* ------------------------------------------------------------------ */\n\ninterface AdaptiveElement {\n type: string;\n text?: string;\n url?: string;\n body?: AdaptiveElement[];\n items?: AdaptiveElement[];\n columns?: Array<{ items?: AdaptiveElement[] }>;\n actions?: Array<{ type: string; title?: string; url?: string; data?: unknown }>;\n [key: string]: unknown;\n}\n\n/** Recursively walk Adaptive Card elements and collect texts, the first image, and buttons. */\nfunction walkAdaptiveElements(\n elements: AdaptiveElement[] | undefined,\n texts: string[],\n buttons: MessageAction[],\n onImage: (url: string) => void,\n) {\n if (!elements) return;\n for (const el of elements) {\n switch (el.type) {\n case \"TextBlock\":\n if (el.text) texts.push(el.text);\n break;\n case \"Image\":\n if (el.url) onImage(el.url);\n break;\n case \"ActionSet\":\n if (el.actions) mapAdaptiveActions(el.actions, buttons);\n break;\n case \"Container\":\n walkAdaptiveElements(el.items, texts, buttons, onImage);\n break;\n case \"ColumnSet\":\n for (const col of el.columns ?? []) {\n walkAdaptiveElements(col.items, texts, buttons, onImage);\n }\n break;\n case \"Column\":\n walkAdaptiveElements(el.items, texts, buttons, onImage);\n break;\n }\n }\n}\n\n/** Parse an Adaptive Card body into { image, title, subtitle, buttons }. */\nfunction parseAdaptiveCardBody(content: Record<string, unknown>) {\n const texts: string[] = [];\n let image: string | undefined;\n const buttons: MessageAction[] = [];\n\n walkAdaptiveElements(\n content.body as AdaptiveElement[] | undefined,\n texts,\n buttons,\n (url) => { image = image ?? url; },\n );\n\n if (Array.isArray(content.actions)) {\n mapAdaptiveActions(content.actions as AdaptiveElement[\"actions\"] & object, buttons);\n }\n\n return { texts, image, buttons };\n}\n\n/**\n * Extract card-like data from an Adaptive Card — used inside carousels.\n */\nfunction adaptiveCardToCardData(\n content: Record<string, unknown>,\n): Record<string, unknown> {\n const { texts, image, buttons } = parseAdaptiveCardBody(content);\n return {\n image,\n title: texts[0] ?? \"\",\n subtitle: texts.slice(1).join(\"\\n\"),\n buttons,\n };\n}\n\nfunction mapAdaptiveCard(\n content: Record<string, unknown>,\n id: string,\n timestamp: number,\n): IncomingMessage {\n const { texts, image, buttons } = parseAdaptiveCardBody(content);\n\n // Fallback text\n const fallback =\n (content.fallbackText as string) ??\n (content.speak as string) ??\n texts.join(\"\\n\");\n\n // If we have an image and a title, render as card\n if (image) {\n return {\n id,\n type: \"card\",\n from: \"bot\",\n data: {\n image,\n title: texts[0] ?? \"\",\n subtitle: texts.slice(1).join(\"\\n\"),\n buttons,\n },\n timestamp,\n };\n }\n\n // If we have buttons, render as buttons message\n if (buttons.length > 0) {\n return {\n id,\n type: \"buttons\",\n from: \"bot\",\n data: {\n text: fallback || \"Adaptive Card\",\n buttons,\n },\n timestamp,\n };\n }\n\n // Plain text fallback\n return {\n id,\n type: \"text\",\n from: \"bot\",\n data: { text: fallback || \"[Adaptive Card]\" },\n timestamp,\n };\n}\n\nfunction mapAdaptiveActions(\n actions: Array<{ type: string; title?: string; url?: string; data?: unknown }>,\n out: MessageAction[],\n) {\n for (const a of actions) {\n const label = a.title ?? \"Action\";\n if (a.type === \"Action.OpenUrl\" && a.url) {\n out.push({ label, url: a.url });\n } else if (a.type === \"Action.Submit\") {\n out.push({ label, value: typeof a.data === \"string\" ? a.data : label });\n } else {\n out.push({ label, value: label });\n }\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Receipt card mapping */\n/* ------------------------------------------------------------------ */\n\nfunction mapReceiptCard(\n content: Receipt[\"content\"],\n id: string,\n timestamp: number,\n): IncomingMessage {\n const lines: string[] = [];\n if (content.title) lines.push(`**${content.title}**`);\n\n if (content.facts) {\n for (const fact of content.facts) {\n lines.push(`${fact.key}: ${fact.value}`);\n }\n }\n\n if (content.items) {\n for (const item of content.items) {\n const price = item.price ? ` — ${item.price}` : \"\";\n lines.push(`- ${item.title ?? \"Item\"}${price}`);\n }\n }\n\n if (content.tax) lines.push(`Tax: ${content.tax}`);\n if (content.total) lines.push(`**Total: ${content.total}**`);\n\n return {\n id,\n type: \"text\",\n from: \"bot\",\n data: { text: lines.join(\"\\n\") },\n timestamp,\n };\n}\n","import type {\n IConnector,\n MessageHandler,\n ConnectHandler,\n DisconnectHandler,\n TypingHandler,\n MessageStatusHandler,\n ChativaContext,\n} from \"@chativa/core\";\nimport type {\n OutgoingMessage,\n HistoryResult,\n IncomingMessage,\n} from \"@chativa/core\";\nimport { DirectLine, ConnectionStatus } from \"botframework-directlinejs\";\nimport type { Activity } from \"botframework-directlinejs\";\nimport { mapActivityToMessage, TYPING_SENTINEL } from \"./mapActivity\";\n\n/** Minimal subscription interface returned by RxJS5 Observable.subscribe(). */\ninterface Unsubscribable {\n unsubscribe(): void;\n}\n\n/**\n * Context passed to custom event handlers — provides the info and methods\n * needed to respond to a bot-initiated event activity.\n */\nexport interface EventHandlerContext {\n /** The raw DirectLine event activity. */\n activity: Activity;\n /** The user ID for this session. */\n userId: string;\n /** The user display name for this session. */\n userName: string;\n /** Send an event activity back to the bot. */\n postEvent(name: string, value?: unknown): void;\n /**\n * Full Chativa context — access messages, chat UI, theme, and event bus.\n * Available when the connector is used via ChatEngine (which injects it).\n */\n chativa: ChativaContext;\n}\n\n/**\n * Handler for a bot-initiated event activity.\n * Keyed by event name (e.g. `\"LocationRequest\"`).\n */\nexport type EventHandler = (ctx: EventHandlerContext) => void;\n\nexport interface DirectLineConnectorOptions {\n /** DirectLine channel secret (server-side only — generates a token). */\n secret?: string;\n /** Pre-fetched DirectLine token. */\n token?: string;\n /** URL of a custom token-generating endpoint (POST, returns { token, conversationId? }). */\n tokenGeneratorUrl?: string;\n /** Override the user ID instead of auto-generating one. */\n userId?: string;\n /** Display name sent with activities. */\n userName?: string;\n /** Sovereign-cloud DirectLine endpoint (e.g. government, china). */\n domain?: string;\n /** BCP-47 locale sent with the webchat/join event and outgoing activities (e.g. \"tr-TR\"). */\n locale?: string;\n /**\n * Extra key-value pairs merged into the `webchat/join` event's `value` payload.\n * Example: `{ language: \"tr\", tenant: \"galataport\" }`\n */\n joinParameters?: Record<string, unknown>;\n /**\n * Custom handlers for bot-initiated event activities, keyed by event name.\n * Example:\n * ```ts\n * eventHandlers: {\n * LocationRequest: (ctx) => {\n * navigator.geolocation.getCurrentPosition((pos) => {\n * ctx.postEvent(\"webchat/location\", {\n * latitude: pos.coords.latitude,\n * longitude: pos.coords.longitude,\n * });\n * });\n * },\n * }\n * ```\n */\n eventHandlers?: Record<string, EventHandler>;\n /**\n * When true, persist conversation state (conversationId, token, watermark)\n * to localStorage so the conversation can be resumed across page reloads.\n */\n resumeConversation?: boolean;\n /**\n * How long (ms) to keep the typing indicator visible after a bot typing\n * signal before auto-clearing it. Each new typing signal resets the timer.\n * Default: 3000. Ignored when `typingUntilMessage` is true.\n */\n typingTimeoutMs?: number;\n /**\n * When true, the typing indicator stays on until the next bot message\n * arrives (no auto-clear timeout).\n */\n typingUntilMessage?: boolean;\n}\n\n/* ── Constants ────────────────────────────────────────────────────── */\n\nconst USER_ID_KEY = \"chativa_directline_userId\";\nconst CONVERSATION_KEY = \"chativa_directline_conversation\";\n\ninterface PersistedConversation {\n conversationId: string;\n token: string;\n watermark?: string;\n userId: string;\n}\n\n/* ── Module-level helpers ─────────────────────────────────────────── */\n\nfunction getOrCreateUserId(): string {\n try {\n const stored = localStorage.getItem(USER_ID_KEY);\n if (stored) return stored;\n } catch {\n // localStorage unavailable (e.g. incognito, SSR)\n }\n const id =\n Math.random().toString(36).slice(2, 15) +\n Math.random().toString(36).slice(2, 15);\n try {\n localStorage.setItem(USER_ID_KEY, id);\n } catch {\n // best-effort\n }\n return id;\n}\n\n/** Extract expiry time (ms since epoch) from a JWT token. */\nfunction getTokenExpiry(token: string): number | null {\n try {\n const payload = JSON.parse(atob(token.split(\".\")[1]));\n return typeof payload.exp === \"number\" ? payload.exp * 1000 : null;\n } catch {\n return null;\n }\n}\n\nasync function fetchToken(\n secret: string,\n userId: string,\n): Promise<{ token: string; conversationId: string }> {\n const res = await fetch(\n \"https://directline.botframework.com/v3/directline/tokens/generate\",\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${secret}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ user: { id: userId, name: userId } }),\n },\n );\n if (!res.ok) {\n throw new Error(`DirectLine token fetch failed: ${res.status}`);\n }\n const data = (await res.json()) as {\n token: string;\n conversationId: string;\n };\n return { token: data.token, conversationId: data.conversationId };\n}\n\nasync function fetchTokenFromUrl(\n url: string,\n): Promise<{ token: string; conversationId?: string; userId?: string }> {\n const res = await fetch(url, { method: \"POST\" });\n if (!res.ok) {\n throw new Error(`Token generator failed: ${res.status}`);\n }\n return (await res.json()) as {\n token: string;\n conversationId?: string;\n userId?: string;\n };\n}\n\n/** Refresh an existing DirectLine token via the REST API. */\nasync function refreshDirectLineToken(\n currentToken: string,\n domain?: string,\n): Promise<{ token: string; conversationId: string }> {\n const base = domain ?? \"https://directline.botframework.com/v3/directline\";\n const res = await fetch(`${base}/tokens/refresh`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${currentToken}` },\n });\n if (!res.ok) {\n throw new Error(`Token refresh failed: ${res.status}`);\n }\n return (await res.json()) as { token: string; conversationId: string };\n}\n\n/**\n * DirectLineConnector — Azure Bot Framework DirectLine v3 adapter.\n *\n * Maps all Bot Framework activity types (hero cards, carousels,\n * suggested actions, images, videos, files, adaptive cards, etc.)\n * into Chativa's native message types.\n */\nexport class DirectLineConnector implements IConnector {\n readonly name = \"directline\";\n readonly addSentToHistory = true;\n\n private directLine!: DirectLine;\n private conversationId!: string;\n private userId!: string;\n private userName: string | undefined;\n private token!: string;\n private options: DirectLineConnectorOptions;\n private chativaCtx: ChativaContext | null = null;\n\n private messageHandler: MessageHandler | null = null;\n private connectHandler: ConnectHandler | null = null;\n private disconnectHandler: DisconnectHandler | null = null;\n private typingHandler: TypingHandler | null = null;\n private messageStatusHandler: MessageStatusHandler | null = null;\n\n private activitySub: Unsubscribable | null = null;\n private connectionSub: Unsubscribable | null = null;\n private typingTimeout: ReturnType<typeof setTimeout> | null = null;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n /** Queue of sent message IDs awaiting echo confirmation. */\n private pendingIds: string[] = [];\n /** True after the first successful connection (used for join vs rejoin). */\n private hasConnectedBefore = false;\n /** Resolves the connect() promise once the bot sends its first message after join. */\n private resolveReady: (() => void) | null = null;\n /** Last known activity watermark — used for conversation resume. */\n private watermark: string | undefined;\n /** When true, skip the next join/rejoin event (used during resume). */\n private _skipNextJoin = false;\n\n constructor(options: DirectLineConnectorOptions) {\n this.options = options;\n }\n\n setContext(ctx: ChativaContext): void {\n this.chativaCtx = ctx;\n }\n\n /**\n * Register (or replace) an event handler for a bot-initiated event activity.\n * Can be called before or after `connect()`.\n *\n * @example\n * ```ts\n * connector.addEventHandler(\"LocationRequest\", (ctx) => {\n * navigator.geolocation.getCurrentPosition((pos) => {\n * ctx.postEvent(\"webchat/location\", { latitude: pos.coords.latitude, ... });\n * });\n * });\n * ```\n */\n addEventHandler(name: string, handler: EventHandler): void {\n this.options.eventHandlers ??= {};\n this.options.eventHandlers[name] = handler;\n }\n\n /** Remove a previously registered event handler by name. */\n removeEventHandler(name: string): boolean {\n if (!this.options.eventHandlers?.[name]) return false;\n delete this.options.eventHandlers[name];\n return true;\n }\n\n /** Check whether an event handler is registered for the given name. */\n hasEventHandler(name: string): boolean {\n return !!this.options.eventHandlers?.[name];\n }\n\n /** Return the names of all registered event handlers. */\n getEventHandlerNames(): string[] {\n return Object.keys(this.options.eventHandlers ?? {});\n }\n\n async connect(): Promise<void> {\n this.userId = this.options.userId ?? getOrCreateUserId();\n this.userName = this.options.userName;\n\n // ── Try to resume a persisted conversation ────────────────────\n let isResuming = false;\n if (this.options.resumeConversation) {\n const persisted = this.loadPersistedConversation();\n if (persisted) {\n try {\n const refreshed = await refreshDirectLineToken(\n persisted.token,\n this.options.domain,\n );\n this.token = refreshed.token;\n this.conversationId = persisted.conversationId;\n this.watermark = persisted.watermark;\n this.userId = persisted.userId;\n isResuming = true;\n } catch {\n // Persisted token expired or invalid — start fresh\n this.clearPersistedConversation();\n }\n }\n }\n\n // ── Acquire token (fresh conversation) ────────────────────────\n if (!isResuming) {\n if (this.options.tokenGeneratorUrl) {\n const result = await fetchTokenFromUrl(\n this.options.tokenGeneratorUrl,\n );\n this.token = result.token;\n if (result.conversationId)\n this.conversationId = result.conversationId;\n if (result.userId) this.userId = result.userId;\n } else if (this.options.token) {\n this.token = this.options.token;\n } else if (this.options.secret) {\n const result = await fetchToken(\n this.options.secret,\n this.userId,\n );\n this.token = result.token;\n this.conversationId = result.conversationId;\n } else {\n throw new Error(\n \"DirectLineConnector: provide token, secret, or tokenGeneratorUrl.\",\n );\n }\n }\n\n // ── Schedule automatic token refresh ──────────────────────────\n this.scheduleTokenRefresh();\n\n // ── Create DirectLine instance ────────────────────────────────\n this.directLine = new DirectLine({\n token: this.token,\n domain: this.options.domain,\n ...(isResuming\n ? {\n conversationId: this.conversationId,\n watermark: this.watermark,\n }\n : {}),\n });\n\n if (isResuming) {\n this.hasConnectedBefore = true;\n this._skipNextJoin = true;\n }\n\n // ── Wait for connection ───────────────────────────────────────\n const ready = new Promise<void>((resolve) => {\n this.resolveReady = resolve;\n });\n\n this.startListening(isResuming);\n\n await ready;\n this.connectHandler?.();\n\n if (this.options.resumeConversation) {\n this.persistConversation();\n }\n }\n\n async disconnect(): Promise<void> {\n this.activitySub?.unsubscribe();\n this.activitySub = null;\n this.connectionSub?.unsubscribe();\n this.connectionSub = null;\n this.clearTypingTimeout();\n this.clearRefreshTimer();\n\n try {\n this.directLine?.end();\n } catch {\n // DirectLine.end() may throw if already ended\n }\n\n this.messageHandler = null;\n this.connectHandler = null;\n this.disconnectHandler = null;\n this.typingHandler = null;\n this.messageStatusHandler = null;\n }\n\n /** Clear persisted conversation state and reset watermark. */\n clearConversation(): void {\n this.watermark = undefined;\n this.clearPersistedConversation();\n }\n\n async sendMessage(message: OutgoingMessage): Promise<void> {\n this.pendingIds.push(message.id);\n // Mark as \"sent\" immediately so it shows before the echo arrives\n this.messageStatusHandler?.(message.id, \"sent\");\n return new Promise<void>((resolve, reject) => {\n this.directLine\n .postActivity({\n type: \"message\",\n from: {\n id: this.userId,\n name: this.userName ?? this.userId,\n },\n text: (message.data as { text?: string }).text ?? \"\",\n conversation: { id: this.conversationId },\n channelId: \"directline\",\n ...(this.options.locale\n ? { locale: this.options.locale }\n : {}),\n timestamp: new Date().toISOString(),\n id: message.id,\n })\n .subscribe({\n next: () => resolve(),\n error: (err: unknown) => reject(err),\n });\n });\n }\n\n async sendFile(file: File): Promise<void> {\n const domain =\n this.options.domain ??\n \"https://directline.botframework.com/v3/directline\";\n const url = `${domain}/conversations/${this.conversationId}/upload?userId=${encodeURIComponent(this.userId)}`;\n\n const formData = new FormData();\n formData.append(\"file\", file, file.name);\n\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${this.token}` },\n body: formData,\n });\n\n if (!res.ok) {\n throw new Error(`DirectLine file upload failed: ${res.status}`);\n }\n }\n\n async sendFeedback(\n messageId: string,\n feedback: \"like\" | \"dislike\",\n ): Promise<void> {\n // Look up the correlationId from the stored message's channelData\n const msg = this.chativaCtx?.messages\n .getAll()\n .find((m) => m.id === messageId);\n const correlationId = (\n msg?.data?.channelData as Record<string, unknown> | undefined\n )?.correlationId;\n\n if (!correlationId) {\n console.warn(\n \"[DirectLineConnector] sendFeedback: no correlationId found for message\",\n messageId,\n );\n return;\n }\n\n // Bot expects numeric: 0 = like, 1 = dislike\n const feedbackType = feedback === \"like\" ? 0 : 1;\n\n return new Promise<void>((resolve, reject) => {\n this.directLine\n .postActivity({\n type: \"event\",\n name: \"webchat/messageFeedback\",\n from: { id: this.userId, name: this.userId },\n value: { correlationId, feedbackType },\n })\n .subscribe({\n next: () => resolve(),\n error: (err: unknown) => reject(err),\n });\n });\n }\n\n async loadHistory(cursor?: string): Promise<HistoryResult> {\n const domain =\n this.options.domain ??\n \"https://directline.botframework.com/v3/directline\";\n const url = cursor\n ? `${domain}/conversations/${this.conversationId}/activities?watermark=${encodeURIComponent(cursor)}`\n : `${domain}/conversations/${this.conversationId}/activities`;\n\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${this.token}` },\n });\n\n if (!res.ok) {\n throw new Error(`DirectLine history fetch failed: ${res.status}`);\n }\n\n const data = (await res.json()) as {\n activities: Activity[];\n watermark: string;\n };\n\n const messages: IncomingMessage[] = [];\n for (const activity of data.activities) {\n // User's own messages — mapActivityToMessage filters these out (live dedup),\n // but history needs them.\n if (\n activity.from.id === this.userId &&\n activity.type === \"message\"\n ) {\n const msg = activity as Activity & { text?: string };\n if (msg.text) {\n messages.push({\n id:\n activity.id ??\n `dl-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,\n type: \"text\",\n from: \"user\",\n data: { text: msg.text },\n timestamp: activity.timestamp\n ? new Date(activity.timestamp).getTime()\n : Date.now(),\n });\n }\n continue;\n }\n\n const result = mapActivityToMessage(activity, this.userId);\n if (result !== null && result !== TYPING_SENTINEL) {\n messages.push(result);\n }\n }\n\n return {\n messages,\n hasMore: false,\n cursor: data.watermark,\n };\n }\n\n onMessage(callback: MessageHandler): void {\n this.messageHandler = callback;\n }\n\n onConnect(callback: ConnectHandler): void {\n this.connectHandler = callback;\n }\n\n onDisconnect(callback: DisconnectHandler): void {\n this.disconnectHandler = callback;\n }\n\n onTyping(callback: TypingHandler): void {\n this.typingHandler = callback;\n }\n\n onMessageStatus(callback: MessageStatusHandler): void {\n this.messageStatusHandler = callback;\n }\n\n /* ── Private helpers ───────────────────────────────────────────── */\n\n /**\n * Subscribe to DirectLine connectionStatus$ and activity$ observables.\n * Extracted so it can be re-used after an ExpiredToken reconnect.\n */\n private startListening(resolveOnOnline: boolean) {\n this.connectionSub = this.directLine.connectionStatus$.subscribe(\n (status: ConnectionStatus) => {\n switch (status) {\n case ConnectionStatus.Online:\n this.sendJoinEvent();\n // Resumed / reconnected conversations resolve immediately\n if (resolveOnOnline && this.resolveReady) {\n this.resolveReady();\n this.resolveReady = null;\n }\n break;\n case ConnectionStatus.ExpiredToken:\n this.handleExpiredToken();\n break;\n case ConnectionStatus.FailedToConnect:\n if (this.options.resumeConversation) {\n this.clearPersistedConversation();\n }\n this.disconnectHandler?.(\"Failed to connect\");\n break;\n case ConnectionStatus.Ended:\n this.disconnectHandler?.(\"Connection ended\");\n break;\n }\n },\n );\n\n this.activitySub = this.directLine.activity$.subscribe((activity) => {\n try {\n // Track watermark and conversationId from every activity\n if (activity.id) this.watermark = activity.id;\n if (!this.conversationId && activity.conversation?.id) {\n this.conversationId = activity.conversation.id;\n }\n\n // Skip own echoed activities\n if (activity.from.id === this.userId) {\n // Echoed user message → mark the original as \"read\"\n if (activity.type === \"message\") {\n const pendingId = this.pendingIds.shift();\n if (pendingId) {\n this.messageStatusHandler?.(pendingId, \"read\");\n }\n }\n return;\n }\n\n // Bot-initiated event\n if (activity.type === \"event\" && activity.name) {\n // Built-in: DisableFeedbackButton — mark the message as feedback-sent\n if (\n activity.name === \"DisableFeedbackButton\" &&\n activity.value\n ) {\n const val = activity.value as {\n CorrelationId?: string;\n FeedbackType?: number;\n };\n if (val.CorrelationId) {\n this.handleDisableFeedback(\n val.CorrelationId,\n val.FeedbackType,\n );\n }\n }\n\n // Dispatch to custom event handler (if registered)\n const handler = this.options.eventHandlers?.[activity.name];\n if (handler) {\n handler(this.createEventContext(activity));\n }\n return;\n }\n\n const result = mapActivityToMessage(activity, this.userId);\n\n if (result === TYPING_SENTINEL) {\n this.handleTyping();\n return;\n }\n\n if (result !== null) {\n // Clear typing indicator when a message arrives\n this.clearTypingTimeout();\n this.typingHandler?.(false);\n\n // First bot message → resolve connect() and signal \"connected\"\n if (this.resolveReady) {\n this.resolveReady();\n this.resolveReady = null;\n }\n\n this.messageHandler?.(result);\n\n // Persist state after delivering a message\n if (this.options.resumeConversation) {\n this.persistConversation();\n }\n }\n } catch (err) {\n console.warn(\n \"[DirectLineConnector] Activity mapping error:\",\n err,\n );\n }\n });\n }\n\n /** Build the context object passed to custom event handlers. */\n private createEventContext(activity: Activity): EventHandlerContext {\n const from = { id: this.userId, name: this.userName ?? this.userId };\n return {\n activity,\n userId: this.userId,\n userName: this.userName ?? this.userId,\n postEvent: (name: string, value?: unknown) => {\n this.directLine\n .postActivity({\n type: \"event\",\n name,\n from,\n ...(this.options.locale\n ? { locale: this.options.locale }\n : {}),\n value,\n })\n .subscribe();\n },\n chativa: this.chativaCtx!,\n };\n }\n\n /** Send webchat/join (first connect) or webchat/rejoin (reconnect) event. */\n private sendJoinEvent() {\n const locale = this.options.locale;\n const from = { id: this.userId, name: this.userName ?? this.userId };\n\n // Skip join/rejoin when resuming a persisted conversation\n if (this._skipNextJoin) {\n this._skipNextJoin = false;\n this.hasConnectedBefore = true;\n this.directLine\n .postActivity({\n type: \"event\",\n name: \"webchat/rejoin\",\n from,\n ...(locale ? { locale } : {}),\n value: { ...(locale ? { language: locale } : {}) },\n })\n .subscribe();\n return;\n }\n this.directLine\n .postActivity({\n type: \"event\",\n name: \"webchat/join\",\n from,\n ...(locale ? { locale } : {}),\n value: {\n ...(locale ? { language: locale } : {}),\n ...this.options.joinParameters,\n },\n })\n .subscribe();\n }\n\n /** Handle DisableFeedbackButton event — find the message by correlationId and patch it. */\n private handleDisableFeedback(\n correlationId: string,\n feedbackType?: number,\n ) {\n const messages = this.chativaCtx?.messages.getAll();\n if (!messages) return;\n const msg = messages.find(\n (m) =>\n (m.data?.channelData as Record<string, unknown> | undefined)\n ?.correlationId === correlationId,\n );\n if (msg) {\n this.chativaCtx!.messages.update(msg.id, {\n data: { ...msg.data, feedbackDisabled: true, feedbackType },\n });\n }\n }\n\n private handleTyping() {\n this.clearTypingTimeout();\n this.typingHandler?.(true);\n if (this.options.typingUntilMessage) {\n // No timer — rely on next bot message (handled by ChatEngine) to clear.\n return;\n }\n const ms = this.options.typingTimeoutMs ?? 3000;\n this.typingTimeout = setTimeout(() => {\n this.typingHandler?.(false);\n this.typingTimeout = null;\n }, ms);\n }\n\n private clearTypingTimeout() {\n if (this.typingTimeout !== null) {\n clearTimeout(this.typingTimeout);\n this.typingTimeout = null;\n }\n }\n\n /* ── Token refresh ──────────────────────────────────────────────── */\n\n /** Schedule a token refresh 60 seconds before expiry. */\n private scheduleTokenRefresh() {\n this.clearRefreshTimer();\n const expiry = getTokenExpiry(this.token);\n if (!expiry) return;\n\n const delay = expiry - Date.now() - 60_000;\n if (delay <= 0) {\n // Token is already about to expire — refresh immediately\n this.refreshTokenNow();\n return;\n }\n this.refreshTimer = setTimeout(() => this.refreshTokenNow(), delay);\n }\n\n /** Pre-emptively refresh the token before it expires. */\n private async refreshTokenNow() {\n try {\n const result = await refreshDirectLineToken(\n this.token,\n this.options.domain,\n );\n this.token = result.token;\n this.scheduleTokenRefresh();\n if (this.options.resumeConversation) {\n this.persistConversation();\n }\n } catch (err) {\n console.warn(\"[DirectLineConnector] Token refresh failed:\", err);\n }\n }\n\n /**\n * Called when DirectLine emits ExpiredToken status.\n * Refreshes the token and recreates the DirectLine connection.\n */\n private async handleExpiredToken() {\n try {\n const result = await refreshDirectLineToken(\n this.token,\n this.options.domain,\n );\n this.token = result.token;\n this.scheduleTokenRefresh();\n } catch {\n if (this.options.resumeConversation) {\n this.clearPersistedConversation();\n }\n this.disconnectHandler?.(\"Token expired and refresh failed\");\n return;\n }\n\n // Tear down old DirectLine\n this.activitySub?.unsubscribe();\n this.connectionSub?.unsubscribe();\n this.clearTypingTimeout();\n try {\n this.directLine.end();\n } catch {\n /* already ended */\n }\n\n // Recreate with new token, preserving conversation\n this.directLine = new DirectLine({\n token: this.token,\n domain: this.options.domain,\n conversationId: this.conversationId,\n watermark: this.watermark,\n });\n\n this.startListening(true);\n\n if (this.options.resumeConversation) {\n this.persistConversation();\n }\n }\n\n private clearRefreshTimer() {\n if (this.refreshTimer !== null) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n /* ── Conversation persistence ───────────────────────────────────── */\n\n private persistConversation() {\n if (!this.conversationId || !this.token) return;\n try {\n const data: PersistedConversation = {\n conversationId: this.conversationId,\n token: this.token,\n watermark: this.watermark,\n userId: this.userId,\n };\n localStorage.setItem(CONVERSATION_KEY, JSON.stringify(data));\n } catch {\n // localStorage unavailable\n }\n }\n\n private loadPersistedConversation(): PersistedConversation | null {\n try {\n const raw = localStorage.getItem(CONVERSATION_KEY);\n if (!raw) return null;\n return JSON.parse(raw) as PersistedConversation;\n } catch {\n return null;\n }\n }\n\n private clearPersistedConversation() {\n try {\n localStorage.removeItem(CONVERSATION_KEY);\n } catch {\n // best-effort\n }\n }\n}\n"],"names":["TYPING_SENTINEL","CT_HERO","CT_THUMBNAIL","CT_ADAPTIVE","CT_SIGNIN","CT_OAUTH","CT_RECEIPT","CT_AUDIO","CT_VIDEO","CT_ANIMATION","CT_FLEX","mapActivityToMessage","activity","userId","msg","id","timestamp","channelData","suggestedActions","mapSuggestedActions","result","mapAttachments","attachments","layout","cardTypes","adaptiveCardToCardData","mapHeroLikeCard","mapSingleAttachment","att","ct","content","mapAdaptiveCard","mapCardButtons","mapReceiptCard","mediaUrl","buttons","btn","label","actions","a","walkAdaptiveElements","elements","texts","onImage","el","mapAdaptiveActions","col","parseAdaptiveCardBody","image","url","fallback","out","lines","fact","item","price","USER_ID_KEY","CONVERSATION_KEY","getOrCreateUserId","stored","getTokenExpiry","token","payload","fetchToken","secret","res","data","fetchTokenFromUrl","refreshDirectLineToken","currentToken","domain","DirectLineConnector","options","ctx","name","handler","isResuming","persisted","refreshed","DirectLine","ready","resolve","message","reject","err","file","formData","messageId","feedback","correlationId","m","feedbackType","cursor","messages","callback","resolveOnOnline","status","ConnectionStatus","pendingId","val","from","value","locale","ms","expiry","delay","raw"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/mapActivity.ts","../src/DirectLineConnector.ts"],"sourcesContent":["/**\n * Pure mapping functions that convert DirectLine activities\n * into Chativa IncomingMessage structures.\n *\n * No side-effects — all functions are stateless and easily testable.\n */\n\nimport type {\n Activity,\n Message,\n CardAction,\n Attachment,\n HeroCard,\n Thumbnail,\n Signin,\n Receipt,\n AudioCard,\n VideoCard,\n AnimationCard,\n AdaptiveCard,\n FlexCard,\n} from \"botframework-directlinejs\";\nimport type { IncomingMessage, MessageAction } from \"@chativa/core\";\n\n/* ------------------------------------------------------------------ */\n/* Sentinel returned for typing activities */\n/* ------------------------------------------------------------------ */\n\nexport const TYPING_SENTINEL = Symbol(\"typing\");\nexport type MapResult = IncomingMessage | typeof TYPING_SENTINEL | null;\n\n/* ------------------------------------------------------------------ */\n/* Content-type constants */\n/* ------------------------------------------------------------------ */\n\nconst CT_HERO = \"application/vnd.microsoft.card.hero\";\nconst CT_THUMBNAIL = \"application/vnd.microsoft.card.thumbnail\";\nconst CT_ADAPTIVE = \"application/vnd.microsoft.card.adaptive\";\nconst CT_SIGNIN = \"application/vnd.microsoft.card.signin\";\nconst CT_OAUTH = \"application/vnd.microsoft.card.oauth\";\nconst CT_RECEIPT = \"application/vnd.microsoft.card.receipt\";\nconst CT_AUDIO = \"application/vnd.microsoft.card.audio\";\nconst CT_VIDEO = \"application/vnd.microsoft.card.video\";\nconst CT_ANIMATION = \"application/vnd.microsoft.card.animation\";\nconst CT_FLEX = \"application/vnd.microsoft.card.flex\";\n\n/* ------------------------------------------------------------------ */\n/* Main entry point */\n/* ------------------------------------------------------------------ */\n\n/**\n * Convert a DirectLine Activity into a Chativa IncomingMessage.\n *\n * Returns:\n * - `IncomingMessage` for renderable messages\n * - `TYPING_SENTINEL` for typing indicators (handled by the connector)\n * - `null` for activities that should be ignored (echo, events, etc.)\n */\nexport function mapActivityToMessage(\n activity: Activity,\n userId: string,\n): MapResult {\n // Filter out echoed user messages\n if (activity.from.id === userId) return null;\n\n // Typing indicator\n if (activity.type === \"typing\") return TYPING_SENTINEL;\n\n // Only process message activities\n if (activity.type !== \"message\") return null;\n\n const msg = activity as Message;\n const id = msg.id ?? `dl-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n const timestamp = msg.timestamp ? new Date(msg.timestamp).getTime() : Date.now();\n\n // Preserve channelData (e.g. correlationId used for feedback)\n const channelData = (msg as unknown as { channelData?: Record<string, unknown> }).channelData;\n\n // Map suggested actions (may be used as top-level actions or as quick-reply)\n const suggestedActions = mapSuggestedActions(msg);\n\n // If there are attachments, process them\n if (msg.attachments && msg.attachments.length > 0) {\n const result = mapAttachments(msg, id, timestamp);\n if (result) {\n if (suggestedActions.length > 0) result.actions = suggestedActions;\n if (channelData) result.data.channelData = channelData;\n }\n return result;\n }\n\n // Text + suggested actions → quick-reply\n if (suggestedActions.length > 0) {\n return {\n id,\n type: \"quick-reply\",\n from: \"bot\",\n data: { text: msg.text ?? \"\", actions: suggestedActions, ...(channelData ? { channelData } : {}) },\n timestamp,\n };\n }\n\n // Plain text\n if (msg.text) {\n return {\n id,\n type: \"text\",\n from: \"bot\",\n data: { text: msg.text, ...(channelData ? { channelData } : {}) },\n timestamp,\n };\n }\n\n // Nothing meaningful\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Attachment mapping */\n/* ------------------------------------------------------------------ */\n\nfunction mapAttachments(\n msg: Message,\n id: string,\n timestamp: number,\n): IncomingMessage | null {\n const attachments = msg.attachments!;\n const layout = msg.attachmentLayout;\n\n // Multiple cards with carousel layout\n const cardTypes = [CT_HERO, CT_THUMBNAIL, CT_FLEX, CT_ADAPTIVE];\n const allCards = attachments.every((a) => cardTypes.includes(a.contentType));\n\n if (allCards && (attachments.length > 1 || layout === \"carousel\")) {\n return {\n id,\n type: \"carousel\",\n from: \"bot\",\n data: {\n cards: attachments.map((a) => {\n if (a.contentType === CT_ADAPTIVE) {\n return adaptiveCardToCardData(\n (a as AdaptiveCard).content as Record<string, unknown>,\n );\n }\n return mapHeroLikeCard((a as HeroCard | Thumbnail | FlexCard).content);\n }),\n },\n timestamp,\n };\n }\n\n // Single attachment\n return mapSingleAttachment(attachments[0], msg, id, timestamp);\n}\n\nfunction mapSingleAttachment(\n att: Attachment,\n msg: Message,\n id: string,\n timestamp: number,\n): IncomingMessage | null {\n const ct = att.contentType;\n\n // Hero / Thumbnail / Flex card\n if (ct === CT_HERO || ct === CT_THUMBNAIL || ct === CT_FLEX) {\n const content = (att as HeroCard | Thumbnail | FlexCard).content;\n return {\n id,\n type: \"card\",\n from: \"bot\",\n data: mapHeroLikeCard(content),\n timestamp,\n };\n }\n\n // Adaptive card — simple parse\n if (ct === CT_ADAPTIVE) {\n return mapAdaptiveCard((att as AdaptiveCard).content, id, timestamp);\n }\n\n // Signin / OAuth card\n if (ct === CT_SIGNIN || ct === CT_OAUTH) {\n const content = (att as Signin).content;\n return {\n id,\n type: \"buttons\",\n from: \"bot\",\n data: {\n text: content.text ?? \"Please sign in\",\n buttons: mapCardButtons(content.buttons),\n },\n timestamp,\n };\n }\n\n // Receipt card\n if (ct === CT_RECEIPT) {\n return mapReceiptCard((att as Receipt).content, id, timestamp);\n }\n\n // Video card\n if (ct === CT_VIDEO) {\n const content = (att as VideoCard).content;\n const mediaUrl = content.media?.[0]?.url;\n if (!mediaUrl) return null;\n return {\n id,\n type: \"video\",\n from: \"bot\",\n data: {\n src: mediaUrl,\n poster: content.image?.url,\n caption: content.title ?? msg.text,\n },\n timestamp,\n };\n }\n\n // Audio card\n if (ct === CT_AUDIO) {\n const content = (att as AudioCard).content;\n const mediaUrl = content.media?.[0]?.url;\n if (!mediaUrl) return null;\n return {\n id,\n type: \"file\",\n from: \"bot\",\n data: {\n url: mediaUrl,\n name: content.title ?? \"audio\",\n mimeType: \"audio/mpeg\",\n },\n timestamp,\n };\n }\n\n // Animation card (typically GIFs)\n if (ct === CT_ANIMATION) {\n const content = (att as AnimationCard).content;\n const mediaUrl = content.media?.[0]?.url;\n if (!mediaUrl) return null;\n return {\n id,\n type: \"image\",\n from: \"bot\",\n data: {\n src: mediaUrl,\n caption: content.title ?? msg.text,\n },\n timestamp,\n };\n }\n\n // Image attachment (contentType starts with \"image/\")\n if (ct.startsWith(\"image/\") && \"contentUrl\" in att) {\n return {\n id,\n type: \"image\",\n from: \"bot\",\n data: {\n src: att.contentUrl,\n alt: att.name,\n caption: msg.text,\n },\n timestamp,\n };\n }\n\n // Video file attachment\n if (ct.startsWith(\"video/\") && \"contentUrl\" in att) {\n return {\n id,\n type: \"video\",\n from: \"bot\",\n data: {\n src: att.contentUrl,\n caption: msg.text,\n },\n timestamp,\n };\n }\n\n // Generic file attachment\n if (\"contentUrl\" in att) {\n return {\n id,\n type: \"file\",\n from: \"bot\",\n data: {\n url: att.contentUrl,\n name: att.name ?? \"file\",\n mimeType: ct,\n },\n timestamp,\n };\n }\n\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Hero-like card mapping (hero, thumbnail, flex share same shape) */\n/* ------------------------------------------------------------------ */\n\nfunction mapHeroLikeCard(content: HeroCard[\"content\"]): Record<string, unknown> {\n return {\n image: content.images?.[0]?.url,\n title: content.title ?? \"\",\n subtitle: content.subtitle ?? content.text,\n buttons: mapCardButtons(content.buttons),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Card button / action mapping */\n/* ------------------------------------------------------------------ */\n\nexport function mapCardButtons(\n buttons?: CardAction[],\n): MessageAction[] {\n if (!buttons || buttons.length === 0) return [];\n\n return buttons.map((btn): MessageAction => {\n const label = (\"title\" in btn ? btn.title : undefined) ?? String(btn.value ?? \"\");\n\n switch (btn.type) {\n case \"openUrl\":\n case \"signin\":\n return { label, url: String(btn.value ?? \"\") };\n\n case \"call\":\n return { label, url: String(btn.value ?? \"\") };\n\n case \"imBack\":\n case \"postBack\":\n case \"messageBack\":\n default:\n return { label, value: String(btn.value ?? label) };\n }\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Suggested actions mapping */\n/* ------------------------------------------------------------------ */\n\nfunction mapSuggestedActions(msg: Message): MessageAction[] {\n const actions = msg.suggestedActions?.actions;\n if (!actions || actions.length === 0) return [];\n\n return actions.map((a): MessageAction => {\n const label = (\"title\" in a ? a.title : undefined) ?? String(a.value ?? \"\");\n if (a.type === \"openUrl\") {\n return { label, url: String(a.value ?? \"\") };\n }\n return { label, value: String(a.value ?? label) };\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Adaptive Card — simple parse */\n/* ------------------------------------------------------------------ */\n\ninterface AdaptiveElement {\n type: string;\n text?: string;\n url?: string;\n body?: AdaptiveElement[];\n items?: AdaptiveElement[];\n columns?: Array<{ items?: AdaptiveElement[] }>;\n actions?: Array<{ type: string; title?: string; url?: string; data?: unknown }>;\n [key: string]: unknown;\n}\n\n/** Recursively walk Adaptive Card elements and collect texts, the first image, and buttons. */\nfunction walkAdaptiveElements(\n elements: AdaptiveElement[] | undefined,\n texts: string[],\n buttons: MessageAction[],\n onImage: (url: string) => void,\n) {\n if (!elements) return;\n for (const el of elements) {\n switch (el.type) {\n case \"TextBlock\":\n if (el.text) texts.push(el.text);\n break;\n case \"Image\":\n if (el.url) onImage(el.url);\n break;\n case \"ActionSet\":\n if (el.actions) mapAdaptiveActions(el.actions, buttons);\n break;\n case \"Container\":\n walkAdaptiveElements(el.items, texts, buttons, onImage);\n break;\n case \"ColumnSet\":\n for (const col of el.columns ?? []) {\n walkAdaptiveElements(col.items, texts, buttons, onImage);\n }\n break;\n case \"Column\":\n walkAdaptiveElements(el.items, texts, buttons, onImage);\n break;\n }\n }\n}\n\n/** Parse an Adaptive Card body into { image, title, subtitle, buttons }. */\nfunction parseAdaptiveCardBody(content: Record<string, unknown>) {\n const texts: string[] = [];\n let image: string | undefined;\n const buttons: MessageAction[] = [];\n\n walkAdaptiveElements(\n content.body as AdaptiveElement[] | undefined,\n texts,\n buttons,\n (url) => { image = image ?? url; },\n );\n\n if (Array.isArray(content.actions)) {\n mapAdaptiveActions(content.actions as AdaptiveElement[\"actions\"] & object, buttons);\n }\n\n return { texts, image, buttons };\n}\n\n/**\n * Extract card-like data from an Adaptive Card — used inside carousels.\n */\nfunction adaptiveCardToCardData(\n content: Record<string, unknown>,\n): Record<string, unknown> {\n const { texts, image, buttons } = parseAdaptiveCardBody(content);\n return {\n image,\n title: texts[0] ?? \"\",\n subtitle: texts.slice(1).join(\"\\n\"),\n buttons,\n };\n}\n\nfunction mapAdaptiveCard(\n content: Record<string, unknown>,\n id: string,\n timestamp: number,\n): IncomingMessage {\n const { texts, image, buttons } = parseAdaptiveCardBody(content);\n\n // Fallback text\n const fallback =\n (content.fallbackText as string) ??\n (content.speak as string) ??\n texts.join(\"\\n\");\n\n // If we have an image and a title, render as card\n if (image) {\n return {\n id,\n type: \"card\",\n from: \"bot\",\n data: {\n image,\n title: texts[0] ?? \"\",\n subtitle: texts.slice(1).join(\"\\n\"),\n buttons,\n },\n timestamp,\n };\n }\n\n // If we have buttons, render as buttons message\n if (buttons.length > 0) {\n return {\n id,\n type: \"buttons\",\n from: \"bot\",\n data: {\n text: fallback || \"Adaptive Card\",\n buttons,\n },\n timestamp,\n };\n }\n\n // Plain text fallback\n return {\n id,\n type: \"text\",\n from: \"bot\",\n data: { text: fallback || \"[Adaptive Card]\" },\n timestamp,\n };\n}\n\nfunction mapAdaptiveActions(\n actions: Array<{ type: string; title?: string; url?: string; data?: unknown }>,\n out: MessageAction[],\n) {\n for (const a of actions) {\n const label = a.title ?? \"Action\";\n if (a.type === \"Action.OpenUrl\" && a.url) {\n out.push({ label, url: a.url });\n } else if (a.type === \"Action.Submit\") {\n out.push({ label, value: typeof a.data === \"string\" ? a.data : label });\n } else {\n out.push({ label, value: label });\n }\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Receipt card mapping */\n/* ------------------------------------------------------------------ */\n\nfunction mapReceiptCard(\n content: Receipt[\"content\"],\n id: string,\n timestamp: number,\n): IncomingMessage {\n const lines: string[] = [];\n if (content.title) lines.push(`**${content.title}**`);\n\n if (content.facts) {\n for (const fact of content.facts) {\n lines.push(`${fact.key}: ${fact.value}`);\n }\n }\n\n if (content.items) {\n for (const item of content.items) {\n const price = item.price ? ` — ${item.price}` : \"\";\n lines.push(`- ${item.title ?? \"Item\"}${price}`);\n }\n }\n\n if (content.tax) lines.push(`Tax: ${content.tax}`);\n if (content.total) lines.push(`**Total: ${content.total}**`);\n\n return {\n id,\n type: \"text\",\n from: \"bot\",\n data: { text: lines.join(\"\\n\") },\n timestamp,\n };\n}\n","import type {\n IConnector,\n MessageHandler,\n ConnectHandler,\n DisconnectHandler,\n TypingHandler,\n MessageStatusHandler,\n ChativaContext,\n SurveyPayload,\n} from \"@chativa/core\";\nimport type {\n OutgoingMessage,\n HistoryResult,\n IncomingMessage,\n} from \"@chativa/core\";\nimport { DirectLine, ConnectionStatus } from \"botframework-directlinejs\";\nimport type { Activity } from \"botframework-directlinejs\";\nimport { mapActivityToMessage, TYPING_SENTINEL } from \"./mapActivity\";\n\n/** Minimal subscription interface returned by RxJS5 Observable.subscribe(). */\ninterface Unsubscribable {\n unsubscribe(): void;\n}\n\n/**\n * Context passed to custom event handlers — provides the info and methods\n * needed to respond to a bot-initiated event activity.\n */\nexport interface EventHandlerContext {\n /** The raw DirectLine event activity. */\n activity: Activity;\n /** The user ID for this session. */\n userId: string;\n /** The user display name for this session. */\n userName: string;\n /** Send an event activity back to the bot. */\n postEvent(name: string, value?: unknown): void;\n /**\n * Full Chativa context — access messages, chat UI, theme, and event bus.\n * Available when the connector is used via ChatEngine (which injects it).\n */\n chativa: ChativaContext;\n}\n\n/**\n * Handler for a bot-initiated event activity.\n * Keyed by event name (e.g. `\"LocationRequest\"`).\n */\nexport type EventHandler = (ctx: EventHandlerContext) => void;\n\nexport interface DirectLineConnectorOptions {\n /** DirectLine channel secret (server-side only — generates a token). */\n secret?: string;\n /** Pre-fetched DirectLine token. */\n token?: string;\n /** URL of a custom token-generating endpoint (POST, returns { token, conversationId? }). */\n tokenGeneratorUrl?: string;\n /** Override the user ID instead of auto-generating one. */\n userId?: string;\n /** Display name sent with activities. */\n userName?: string;\n /** Sovereign-cloud DirectLine endpoint (e.g. government, china). */\n domain?: string;\n /** BCP-47 locale sent with the webchat/join event and outgoing activities (e.g. \"tr-TR\"). */\n locale?: string;\n /**\n * Extra key-value pairs merged into the `webchat/join` event's `value` payload.\n * Example: `{ language: \"tr\", tenant: \"galataport\" }`\n */\n joinParameters?: Record<string, unknown>;\n /**\n * Custom handlers for bot-initiated event activities, keyed by event name.\n * Example:\n * ```ts\n * eventHandlers: {\n * LocationRequest: (ctx) => {\n * navigator.geolocation.getCurrentPosition((pos) => {\n * ctx.postEvent(\"webchat/location\", {\n * latitude: pos.coords.latitude,\n * longitude: pos.coords.longitude,\n * });\n * });\n * },\n * }\n * ```\n */\n eventHandlers?: Record<string, EventHandler>;\n /**\n * When true, persist conversation state (conversationId, token, watermark)\n * to localStorage so the conversation can be resumed across page reloads.\n */\n resumeConversation?: boolean;\n /**\n * How long (ms) to keep the typing indicator visible after a bot typing\n * signal before auto-clearing it. Each new typing signal resets the timer.\n * Default: 3000. Ignored when `typingUntilMessage` is true.\n */\n typingTimeoutMs?: number;\n /**\n * When true, the typing indicator stays on until the next bot message\n * arrives (no auto-clear timeout).\n */\n typingUntilMessage?: boolean;\n}\n\n/* ── Constants ────────────────────────────────────────────────────── */\n\nconst USER_ID_KEY = \"chativa_directline_userId\";\nconst CONVERSATION_KEY = \"chativa_directline_conversation\";\n\ninterface PersistedConversation {\n conversationId: string;\n token: string;\n watermark?: string;\n userId: string;\n}\n\n/* ── Module-level helpers ─────────────────────────────────────────── */\n\nfunction getOrCreateUserId(): string {\n try {\n const stored = localStorage.getItem(USER_ID_KEY);\n if (stored) return stored;\n } catch {\n // localStorage unavailable (e.g. incognito, SSR)\n }\n const id =\n Math.random().toString(36).slice(2, 15) +\n Math.random().toString(36).slice(2, 15);\n try {\n localStorage.setItem(USER_ID_KEY, id);\n } catch {\n // best-effort\n }\n return id;\n}\n\n/** Extract expiry time (ms since epoch) from a JWT token. */\nfunction getTokenExpiry(token: string): number | null {\n try {\n const payload = JSON.parse(atob(token.split(\".\")[1]));\n return typeof payload.exp === \"number\" ? payload.exp * 1000 : null;\n } catch {\n return null;\n }\n}\n\nasync function fetchToken(\n secret: string,\n userId: string,\n): Promise<{ token: string; conversationId: string }> {\n const res = await fetch(\n \"https://directline.botframework.com/v3/directline/tokens/generate\",\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${secret}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ user: { id: userId, name: userId } }),\n },\n );\n if (!res.ok) {\n throw new Error(`DirectLine token fetch failed: ${res.status}`);\n }\n const data = (await res.json()) as {\n token: string;\n conversationId: string;\n };\n return { token: data.token, conversationId: data.conversationId };\n}\n\nasync function fetchTokenFromUrl(\n url: string,\n): Promise<{ token: string; conversationId?: string; userId?: string }> {\n const res = await fetch(url, { method: \"POST\" });\n if (!res.ok) {\n throw new Error(`Token generator failed: ${res.status}`);\n }\n return (await res.json()) as {\n token: string;\n conversationId?: string;\n userId?: string;\n };\n}\n\n/** Refresh an existing DirectLine token via the REST API. */\nasync function refreshDirectLineToken(\n currentToken: string,\n domain?: string,\n): Promise<{ token: string; conversationId: string }> {\n const base = domain ?? \"https://directline.botframework.com/v3/directline\";\n const res = await fetch(`${base}/tokens/refresh`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${currentToken}` },\n });\n if (!res.ok) {\n throw new Error(`Token refresh failed: ${res.status}`);\n }\n return (await res.json()) as { token: string; conversationId: string };\n}\n\n/**\n * DirectLineConnector — Azure Bot Framework DirectLine v3 adapter.\n *\n * Maps all Bot Framework activity types (hero cards, carousels,\n * suggested actions, images, videos, files, adaptive cards, etc.)\n * into Chativa's native message types.\n */\nexport class DirectLineConnector implements IConnector {\n readonly name = \"directline\";\n readonly addSentToHistory = true;\n\n private directLine!: DirectLine;\n private conversationId!: string;\n private userId!: string;\n private userName: string | undefined;\n private token!: string;\n private options: DirectLineConnectorOptions;\n private chativaCtx: ChativaContext | null = null;\n\n private messageHandler: MessageHandler | null = null;\n private connectHandler: ConnectHandler | null = null;\n private disconnectHandler: DisconnectHandler | null = null;\n private typingHandler: TypingHandler | null = null;\n private messageStatusHandler: MessageStatusHandler | null = null;\n\n private activitySub: Unsubscribable | null = null;\n private connectionSub: Unsubscribable | null = null;\n private typingTimeout: ReturnType<typeof setTimeout> | null = null;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n /** Queue of sent message IDs awaiting echo confirmation. */\n private pendingIds: string[] = [];\n /** True after the first successful connection (reserved for future join-vs-rejoin logic). */\n private hasConnectedBefore = false;\n /** Resolves the connect() promise once the bot sends its first message after join. */\n private resolveReady: (() => void) | null = null;\n /** Last known activity watermark — used for conversation resume. */\n private watermark: string | undefined;\n /** When true, skip the next join/rejoin event (used during resume). */\n private _skipNextJoin = false;\n\n constructor(options: DirectLineConnectorOptions) {\n this.options = options;\n }\n\n setContext(ctx: ChativaContext): void {\n this.chativaCtx = ctx;\n }\n\n /**\n * Register (or replace) an event handler for a bot-initiated event activity.\n * Can be called before or after `connect()`.\n *\n * @example\n * ```ts\n * connector.addEventHandler(\"LocationRequest\", (ctx) => {\n * navigator.geolocation.getCurrentPosition((pos) => {\n * ctx.postEvent(\"webchat/location\", { latitude: pos.coords.latitude, ... });\n * });\n * });\n * ```\n */\n addEventHandler(name: string, handler: EventHandler): void {\n this.options.eventHandlers ??= {};\n this.options.eventHandlers[name] = handler;\n }\n\n /** Remove a previously registered event handler by name. */\n removeEventHandler(name: string): boolean {\n if (!this.options.eventHandlers?.[name]) return false;\n delete this.options.eventHandlers[name];\n return true;\n }\n\n /** Check whether an event handler is registered for the given name. */\n hasEventHandler(name: string): boolean {\n return !!this.options.eventHandlers?.[name];\n }\n\n /** Return the names of all registered event handlers. */\n getEventHandlerNames(): string[] {\n return Object.keys(this.options.eventHandlers ?? {});\n }\n\n async connect(): Promise<void> {\n this.userId = this.options.userId ?? getOrCreateUserId();\n this.userName = this.options.userName;\n\n // ── Try to resume a persisted conversation ────────────────────\n let isResuming = false;\n if (this.options.resumeConversation) {\n const persisted = this.loadPersistedConversation();\n if (persisted) {\n try {\n const refreshed = await refreshDirectLineToken(\n persisted.token,\n this.options.domain,\n );\n this.token = refreshed.token;\n this.conversationId = persisted.conversationId;\n this.watermark = persisted.watermark;\n this.userId = persisted.userId;\n isResuming = true;\n } catch {\n // Persisted token expired or invalid — start fresh\n this.clearPersistedConversation();\n }\n }\n }\n\n // ── Acquire token (fresh conversation) ────────────────────────\n if (!isResuming) {\n if (this.options.tokenGeneratorUrl) {\n const result = await fetchTokenFromUrl(\n this.options.tokenGeneratorUrl,\n );\n this.token = result.token;\n if (result.conversationId)\n this.conversationId = result.conversationId;\n if (result.userId) this.userId = result.userId;\n } else if (this.options.token) {\n this.token = this.options.token;\n } else if (this.options.secret) {\n const result = await fetchToken(\n this.options.secret,\n this.userId,\n );\n this.token = result.token;\n this.conversationId = result.conversationId;\n } else {\n throw new Error(\n \"DirectLineConnector: provide token, secret, or tokenGeneratorUrl.\",\n );\n }\n }\n\n // ── Schedule automatic token refresh ──────────────────────────\n this.scheduleTokenRefresh();\n\n // ── Create DirectLine instance ────────────────────────────────\n this.directLine = new DirectLine({\n token: this.token,\n domain: this.options.domain,\n ...(isResuming\n ? {\n conversationId: this.conversationId,\n watermark: this.watermark,\n }\n : {}),\n });\n\n if (isResuming) {\n this.hasConnectedBefore = true;\n this._skipNextJoin = true;\n }\n\n // ── Wait for connection ───────────────────────────────────────\n const ready = new Promise<void>((resolve) => {\n this.resolveReady = resolve;\n });\n\n this.startListening(isResuming);\n\n await ready;\n this.connectHandler?.();\n\n if (this.options.resumeConversation) {\n this.persistConversation();\n }\n }\n\n async disconnect(): Promise<void> {\n this.activitySub?.unsubscribe();\n this.activitySub = null;\n this.connectionSub?.unsubscribe();\n this.connectionSub = null;\n this.clearTypingTimeout();\n this.clearRefreshTimer();\n\n try {\n this.directLine?.end();\n } catch {\n // DirectLine.end() may throw if already ended\n }\n\n this.messageHandler = null;\n this.connectHandler = null;\n this.disconnectHandler = null;\n this.typingHandler = null;\n this.messageStatusHandler = null;\n }\n\n /** Clear persisted conversation state and reset watermark. */\n clearConversation(): void {\n this.watermark = undefined;\n this.clearPersistedConversation();\n }\n\n async sendMessage(message: OutgoingMessage): Promise<void> {\n this.pendingIds.push(message.id);\n // Mark as \"sent\" immediately so it shows before the echo arrives\n this.messageStatusHandler?.(message.id, \"sent\");\n return new Promise<void>((resolve, reject) => {\n this.directLine\n .postActivity({\n type: \"message\",\n from: {\n id: this.userId,\n name: this.userName ?? this.userId,\n },\n text: (message.data as { text?: string }).text ?? \"\",\n conversation: { id: this.conversationId },\n channelId: \"directline\",\n ...(this.options.locale\n ? { locale: this.options.locale }\n : {}),\n timestamp: new Date().toISOString(),\n id: message.id,\n })\n .subscribe({\n next: () => resolve(),\n error: (err: unknown) => reject(err),\n });\n });\n }\n\n async sendFile(file: File): Promise<void> {\n const domain =\n this.options.domain ??\n \"https://directline.botframework.com/v3/directline\";\n const url = `${domain}/conversations/${this.conversationId}/upload?userId=${encodeURIComponent(this.userId)}`;\n\n const formData = new FormData();\n formData.append(\"file\", file, file.name);\n\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${this.token}` },\n body: formData,\n });\n\n if (!res.ok) {\n throw new Error(`DirectLine file upload failed: ${res.status}`);\n }\n }\n\n /**\n * Submit an end-of-conversation survey as a DirectLine event activity.\n * Matches the legacy `webchat/customerfeedback` event shape so existing\n * bot flows keep working:\n * value: { rating, comment, type }\n * where `type` is `kind` coerced to a number (defaulting to 1) to preserve\n * compatibility with bots that switch on numeric survey types.\n */\n async sendSurvey(payload: SurveyPayload): Promise<void> {\n const rawType =\n typeof payload.kind === \"number\"\n ? payload.kind\n : payload.kind !== undefined\n ? Number(payload.kind)\n : 1;\n const type = Number.isFinite(rawType) ? rawType : 1;\n\n return new Promise<void>((resolve, reject) => {\n this.directLine\n .postActivity({\n type: \"event\",\n name: \"webchat/customerfeedback\",\n from: { id: this.userId, name: this.userId },\n value: {\n rating: payload.rating,\n comment: payload.comment ?? \"\",\n type,\n },\n })\n .subscribe({\n next: () => resolve(),\n error: (err: unknown) => reject(err),\n });\n });\n }\n\n async sendFeedback(\n messageId: string,\n feedback: \"like\" | \"dislike\",\n ): Promise<void> {\n // Look up the correlationId from the stored message's channelData\n const msg = this.chativaCtx?.messages\n .getAll()\n .find((m) => m.id === messageId);\n const correlationId = (\n msg?.data?.channelData as Record<string, unknown> | undefined\n )?.correlationId;\n\n if (!correlationId) {\n console.warn(\n \"[DirectLineConnector] sendFeedback: no correlationId found for message\",\n messageId,\n );\n return;\n }\n\n // Bot expects numeric: 0 = like, 1 = dislike\n const feedbackType = feedback === \"like\" ? 0 : 1;\n\n return new Promise<void>((resolve, reject) => {\n this.directLine\n .postActivity({\n type: \"event\",\n name: \"webchat/messageFeedback\",\n from: { id: this.userId, name: this.userId },\n value: { correlationId, feedbackType },\n })\n .subscribe({\n next: () => resolve(),\n error: (err: unknown) => reject(err),\n });\n });\n }\n\n async loadHistory(cursor?: string): Promise<HistoryResult> {\n const domain =\n this.options.domain ??\n \"https://directline.botframework.com/v3/directline\";\n const url = cursor\n ? `${domain}/conversations/${this.conversationId}/activities?watermark=${encodeURIComponent(cursor)}`\n : `${domain}/conversations/${this.conversationId}/activities`;\n\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${this.token}` },\n });\n\n if (!res.ok) {\n throw new Error(`DirectLine history fetch failed: ${res.status}`);\n }\n\n const data = (await res.json()) as {\n activities: Activity[];\n watermark: string;\n };\n\n const messages: IncomingMessage[] = [];\n for (const activity of data.activities) {\n // User's own messages — mapActivityToMessage filters these out (live dedup),\n // but history needs them.\n if (\n activity.from.id === this.userId &&\n activity.type === \"message\"\n ) {\n const msg = activity as Activity & { text?: string };\n if (msg.text) {\n messages.push({\n id:\n activity.id ??\n `dl-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,\n type: \"text\",\n from: \"user\",\n data: { text: msg.text },\n timestamp: activity.timestamp\n ? new Date(activity.timestamp).getTime()\n : Date.now(),\n });\n }\n continue;\n }\n\n const result = mapActivityToMessage(activity, this.userId);\n if (result !== null && result !== TYPING_SENTINEL) {\n messages.push(result);\n }\n }\n\n return {\n messages,\n hasMore: false,\n cursor: data.watermark,\n };\n }\n\n onMessage(callback: MessageHandler): void {\n this.messageHandler = callback;\n }\n\n onConnect(callback: ConnectHandler): void {\n this.connectHandler = callback;\n }\n\n onDisconnect(callback: DisconnectHandler): void {\n this.disconnectHandler = callback;\n }\n\n onTyping(callback: TypingHandler): void {\n this.typingHandler = callback;\n }\n\n onMessageStatus(callback: MessageStatusHandler): void {\n this.messageStatusHandler = callback;\n }\n\n /* ── Private helpers ───────────────────────────────────────────── */\n\n /**\n * Subscribe to DirectLine connectionStatus$ and activity$ observables.\n * Extracted so it can be re-used after an ExpiredToken reconnect.\n */\n private startListening(resolveOnOnline: boolean) {\n this.connectionSub = this.directLine.connectionStatus$.subscribe(\n (status: ConnectionStatus) => {\n switch (status) {\n case ConnectionStatus.Online:\n this.sendJoinEvent();\n // Resumed / reconnected conversations resolve immediately\n if (resolveOnOnline && this.resolveReady) {\n this.resolveReady();\n this.resolveReady = null;\n }\n break;\n case ConnectionStatus.ExpiredToken:\n this.handleExpiredToken();\n break;\n case ConnectionStatus.FailedToConnect:\n if (this.options.resumeConversation) {\n this.clearPersistedConversation();\n }\n this.disconnectHandler?.(\"Failed to connect\");\n break;\n case ConnectionStatus.Ended:\n this.disconnectHandler?.(\"Connection ended\");\n break;\n }\n },\n );\n\n this.activitySub = this.directLine.activity$.subscribe((activity) => {\n try {\n // Track watermark and conversationId from every activity\n if (activity.id) this.watermark = activity.id;\n if (!this.conversationId && activity.conversation?.id) {\n this.conversationId = activity.conversation.id;\n }\n\n // Skip own echoed activities\n if (activity.from.id === this.userId) {\n // Echoed user message → mark the original as \"read\"\n if (activity.type === \"message\") {\n const pendingId = this.pendingIds.shift();\n if (pendingId) {\n this.messageStatusHandler?.(pendingId, \"read\");\n }\n }\n return;\n }\n\n // Bot-initiated event\n if (activity.type === \"event\" && activity.name) {\n // Built-in: DisableFeedbackButton — mark the message as feedback-sent\n if (\n activity.name === \"DisableFeedbackButton\" &&\n activity.value\n ) {\n const val = activity.value as {\n CorrelationId?: string;\n FeedbackType?: number;\n };\n if (val.CorrelationId) {\n this.handleDisableFeedback(\n val.CorrelationId,\n val.FeedbackType,\n );\n }\n }\n\n // Dispatch to custom event handler (if registered)\n const handler = this.options.eventHandlers?.[activity.name];\n if (handler) {\n handler(this.createEventContext(activity));\n }\n return;\n }\n\n const result = mapActivityToMessage(activity, this.userId);\n\n if (result === TYPING_SENTINEL) {\n this.handleTyping();\n return;\n }\n\n if (result !== null) {\n // Clear typing indicator when a message arrives\n this.clearTypingTimeout();\n this.typingHandler?.(false);\n\n // First bot message → resolve connect() and signal \"connected\"\n if (this.resolveReady) {\n this.resolveReady();\n this.resolveReady = null;\n }\n\n this.messageHandler?.(result);\n\n // Persist state after delivering a message\n if (this.options.resumeConversation) {\n this.persistConversation();\n }\n }\n } catch (err) {\n console.warn(\n \"[DirectLineConnector] Activity mapping error:\",\n err,\n );\n }\n });\n }\n\n /** Build the context object passed to custom event handlers. */\n private createEventContext(activity: Activity): EventHandlerContext {\n const from = { id: this.userId, name: this.userName ?? this.userId };\n return {\n activity,\n userId: this.userId,\n userName: this.userName ?? this.userId,\n postEvent: (name: string, value?: unknown) => {\n this.directLine\n .postActivity({\n type: \"event\",\n name,\n from,\n ...(this.options.locale\n ? { locale: this.options.locale }\n : {}),\n value,\n })\n .subscribe();\n },\n chativa: this.chativaCtx!,\n };\n }\n\n /** Send webchat/join (first connect) or webchat/rejoin (reconnect) event. */\n private sendJoinEvent() {\n const locale = this.options.locale;\n const from = { id: this.userId, name: this.userName ?? this.userId };\n // Read reserved for future join-vs-rejoin branching; keeps the field alive.\n void this.hasConnectedBefore;\n\n // Skip join/rejoin when resuming a persisted conversation\n if (this._skipNextJoin) {\n this._skipNextJoin = false;\n this.hasConnectedBefore = true;\n this.directLine\n .postActivity({\n type: \"event\",\n name: \"webchat/rejoin\",\n from,\n ...(locale ? { locale } : {}),\n value: { ...(locale ? { language: locale } : {}) },\n })\n .subscribe();\n return;\n }\n this.directLine\n .postActivity({\n type: \"event\",\n name: \"webchat/join\",\n from,\n ...(locale ? { locale } : {}),\n value: {\n ...(locale ? { language: locale } : {}),\n ...this.options.joinParameters,\n },\n })\n .subscribe();\n }\n\n /** Handle DisableFeedbackButton event — find the message by correlationId and patch it. */\n private handleDisableFeedback(\n correlationId: string,\n feedbackType?: number,\n ) {\n const messages = this.chativaCtx?.messages.getAll();\n if (!messages) return;\n const msg = messages.find(\n (m) =>\n (m.data?.channelData as Record<string, unknown> | undefined)\n ?.correlationId === correlationId,\n );\n if (msg) {\n this.chativaCtx!.messages.update(msg.id, {\n data: { ...msg.data, feedbackDisabled: true, feedbackType },\n });\n }\n }\n\n private handleTyping() {\n this.clearTypingTimeout();\n this.typingHandler?.(true);\n if (this.options.typingUntilMessage) {\n // No timer — rely on next bot message (handled by ChatEngine) to clear.\n return;\n }\n const ms = this.options.typingTimeoutMs ?? 3000;\n this.typingTimeout = setTimeout(() => {\n this.typingHandler?.(false);\n this.typingTimeout = null;\n }, ms);\n }\n\n private clearTypingTimeout() {\n if (this.typingTimeout !== null) {\n clearTimeout(this.typingTimeout);\n this.typingTimeout = null;\n }\n }\n\n /* ── Token refresh ──────────────────────────────────────────────── */\n\n /** Schedule a token refresh 60 seconds before expiry. */\n private scheduleTokenRefresh() {\n this.clearRefreshTimer();\n const expiry = getTokenExpiry(this.token);\n if (!expiry) return;\n\n const delay = expiry - Date.now() - 60_000;\n if (delay <= 0) {\n // Token is already about to expire — refresh immediately\n this.refreshTokenNow();\n return;\n }\n this.refreshTimer = setTimeout(() => this.refreshTokenNow(), delay);\n }\n\n /** Pre-emptively refresh the token before it expires. */\n private async refreshTokenNow() {\n try {\n const result = await refreshDirectLineToken(\n this.token,\n this.options.domain,\n );\n this.token = result.token;\n this.scheduleTokenRefresh();\n if (this.options.resumeConversation) {\n this.persistConversation();\n }\n } catch (err) {\n console.warn(\"[DirectLineConnector] Token refresh failed:\", err);\n }\n }\n\n /**\n * Called when DirectLine emits ExpiredToken status.\n * Refreshes the token and recreates the DirectLine connection.\n */\n private async handleExpiredToken() {\n try {\n const result = await refreshDirectLineToken(\n this.token,\n this.options.domain,\n );\n this.token = result.token;\n this.scheduleTokenRefresh();\n } catch {\n if (this.options.resumeConversation) {\n this.clearPersistedConversation();\n }\n this.disconnectHandler?.(\"Token expired and refresh failed\");\n return;\n }\n\n // Tear down old DirectLine\n this.activitySub?.unsubscribe();\n this.connectionSub?.unsubscribe();\n this.clearTypingTimeout();\n try {\n this.directLine.end();\n } catch {\n /* already ended */\n }\n\n // Recreate with new token, preserving conversation\n this.directLine = new DirectLine({\n token: this.token,\n domain: this.options.domain,\n conversationId: this.conversationId,\n watermark: this.watermark,\n });\n\n this.startListening(true);\n\n if (this.options.resumeConversation) {\n this.persistConversation();\n }\n }\n\n private clearRefreshTimer() {\n if (this.refreshTimer !== null) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n /* ── Conversation persistence ───────────────────────────────────── */\n\n private persistConversation() {\n if (!this.conversationId || !this.token) return;\n try {\n const data: PersistedConversation = {\n conversationId: this.conversationId,\n token: this.token,\n watermark: this.watermark,\n userId: this.userId,\n };\n localStorage.setItem(CONVERSATION_KEY, JSON.stringify(data));\n } catch {\n // localStorage unavailable\n }\n }\n\n private loadPersistedConversation(): PersistedConversation | null {\n try {\n const raw = localStorage.getItem(CONVERSATION_KEY);\n if (!raw) return null;\n return JSON.parse(raw) as PersistedConversation;\n } catch {\n return null;\n }\n }\n\n private clearPersistedConversation() {\n try {\n localStorage.removeItem(CONVERSATION_KEY);\n } catch {\n // best-effort\n }\n }\n}\n"],"names":["TYPING_SENTINEL","CT_HERO","CT_THUMBNAIL","CT_ADAPTIVE","CT_SIGNIN","CT_OAUTH","CT_RECEIPT","CT_AUDIO","CT_VIDEO","CT_ANIMATION","CT_FLEX","mapActivityToMessage","activity","userId","msg","id","timestamp","channelData","suggestedActions","mapSuggestedActions","result","mapAttachments","attachments","layout","cardTypes","adaptiveCardToCardData","mapHeroLikeCard","mapSingleAttachment","att","ct","content","mapAdaptiveCard","mapCardButtons","mapReceiptCard","mediaUrl","buttons","btn","label","actions","a","walkAdaptiveElements","elements","texts","onImage","el","mapAdaptiveActions","col","parseAdaptiveCardBody","image","url","fallback","out","lines","fact","item","price","USER_ID_KEY","CONVERSATION_KEY","getOrCreateUserId","stored","getTokenExpiry","token","payload","fetchToken","secret","res","data","fetchTokenFromUrl","refreshDirectLineToken","currentToken","domain","DirectLineConnector","options","ctx","name","handler","isResuming","persisted","refreshed","DirectLine","ready","resolve","message","reject","err","file","formData","rawType","type","messageId","feedback","correlationId","m","feedbackType","cursor","messages","callback","resolveOnOnline","status","ConnectionStatus","pendingId","val","from","value","locale","ms","expiry","delay","raw"],"mappings":";AA4BO,MAAMA,2BAAyB,QAAQ,GAOxCC,IAAU,uCACVC,IAAe,4CACfC,IAAc,2CACdC,IAAY,yCACZC,IAAW,wCACXC,IAAa,0CACbC,IAAW,wCACXC,IAAW,wCACXC,IAAe,4CACfC,IAAU;AAcT,SAASC,EACdC,GACAC,GACW;AAEX,MAAID,EAAS,KAAK,OAAOC,EAAQ,QAAO;AAGxC,MAAID,EAAS,SAAS,SAAU,QAAOZ;AAGvC,MAAIY,EAAS,SAAS,UAAW,QAAO;AAExC,QAAME,IAAMF,GACNG,IAAKD,EAAI,MAAM,MAAM,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC,IACzEE,IAAYF,EAAI,YAAY,IAAI,KAAKA,EAAI,SAAS,EAAE,YAAY,KAAK,IAAA,GAGrEG,IAAeH,EAA6D,aAG5EI,IAAmBC,EAAoBL,CAAG;AAGhD,MAAIA,EAAI,eAAeA,EAAI,YAAY,SAAS,GAAG;AACjD,UAAMM,IAASC,EAAeP,GAAKC,GAAIC,CAAS;AAChD,WAAII,MACEF,EAAiB,SAAS,MAAGE,EAAO,UAAUF,IAC9CD,MAAaG,EAAO,KAAK,cAAcH,KAEtCG;AAAA,EACT;AAGA,SAAIF,EAAiB,SAAS,IACrB;AAAA,IACL,IAAAH;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,EAAE,MAAMD,EAAI,QAAQ,IAAI,SAASI,GAAkB,GAAID,IAAc,EAAE,aAAAA,EAAA,IAAgB,CAAA,EAAC;AAAA,IAC9F,WAAAD;AAAA,EAAA,IAKAF,EAAI,OACC;AAAA,IACL,IAAAC;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,EAAE,MAAMD,EAAI,MAAM,GAAIG,IAAc,EAAE,aAAAA,EAAA,IAAgB,GAAC;AAAA,IAC7D,WAAAD;AAAA,EAAA,IAKG;AACT;AAMA,SAASK,EACPP,GACAC,GACAC,GACwB;AACxB,QAAMM,IAAcR,EAAI,aAClBS,IAAST,EAAI,kBAGbU,IAAY,CAACvB,GAASC,GAAcQ,GAASP,CAAW;AAG9D,SAFiBmB,EAAY,MAAM,CAAC,MAAME,EAAU,SAAS,EAAE,WAAW,CAAC,MAE1DF,EAAY,SAAS,KAAKC,MAAW,cAC7C;AAAA,IACL,IAAAR;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,OAAOO,EAAY,IAAI,CAAC,MAClB,EAAE,gBAAgBnB,IACbsB;AAAA,QACJ,EAAmB;AAAA,MAAA,IAGjBC,EAAiB,EAAsC,OAAO,CACtE;AAAA,IAAA;AAAA,IAEH,WAAAV;AAAA,EAAA,IAKGW,EAAoBL,EAAY,CAAC,GAAGR,GAAKC,GAAIC,CAAS;AAC/D;AAEA,SAASW,EACPC,GACAd,GACAC,GACAC,GACwB;AACxB,QAAMa,IAAKD,EAAI;AAGf,MAAIC,MAAO5B,KAAW4B,MAAO3B,KAAgB2B,MAAOnB,GAAS;AAC3D,UAAMoB,IAAWF,EAAwC;AACzD,WAAO;AAAA,MACL,IAAAb;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAMW,EAAgBI,CAAO;AAAA,MAC7B,WAAAd;AAAA,IAAA;AAAA,EAEJ;AAGA,MAAIa,MAAO1B;AACT,WAAO4B,EAAiBH,EAAqB,SAASb,GAAIC,CAAS;AAIrE,MAAIa,MAAOzB,KAAayB,MAAOxB,GAAU;AACvC,UAAMyB,IAAWF,EAAe;AAChC,WAAO;AAAA,MACL,IAAAb;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,MAAMe,EAAQ,QAAQ;AAAA,QACtB,SAASE,EAAeF,EAAQ,OAAO;AAAA,MAAA;AAAA,MAEzC,WAAAd;AAAA,IAAA;AAAA,EAEJ;AAGA,MAAIa,MAAOvB;AACT,WAAO2B,EAAgBL,EAAgB,SAASb,GAAIC,CAAS;AAI/D,MAAIa,MAAOrB,GAAU;AACnB,UAAMsB,IAAWF,EAAkB,SAC7BM,IAAWJ,EAAQ,QAAQ,CAAC,GAAG;AACrC,WAAKI,IACE;AAAA,MACL,IAAAnB;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,KAAKmB;AAAA,QACL,QAAQJ,EAAQ,OAAO;AAAA,QACvB,SAASA,EAAQ,SAAShB,EAAI;AAAA,MAAA;AAAA,MAEhC,WAAAE;AAAA,IAAA,IAVoB;AAAA,EAYxB;AAGA,MAAIa,MAAOtB,GAAU;AACnB,UAAMuB,IAAWF,EAAkB,SAC7BM,IAAWJ,EAAQ,QAAQ,CAAC,GAAG;AACrC,WAAKI,IACE;AAAA,MACL,IAAAnB;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,KAAKmB;AAAA,QACL,MAAMJ,EAAQ,SAAS;AAAA,QACvB,UAAU;AAAA,MAAA;AAAA,MAEZ,WAAAd;AAAA,IAAA,IAVoB;AAAA,EAYxB;AAGA,MAAIa,MAAOpB,GAAc;AACvB,UAAMqB,IAAWF,EAAsB,SACjCM,IAAWJ,EAAQ,QAAQ,CAAC,GAAG;AACrC,WAAKI,IACE;AAAA,MACL,IAAAnB;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,KAAKmB;AAAA,QACL,SAASJ,EAAQ,SAAShB,EAAI;AAAA,MAAA;AAAA,MAEhC,WAAAE;AAAA,IAAA,IAToB;AAAA,EAWxB;AAGA,SAAIa,EAAG,WAAW,QAAQ,KAAK,gBAAgBD,IACtC;AAAA,IACL,IAAAb;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAKa,EAAI;AAAA,MACT,KAAKA,EAAI;AAAA,MACT,SAASd,EAAI;AAAA,IAAA;AAAA,IAEf,WAAAE;AAAA,EAAA,IAKAa,EAAG,WAAW,QAAQ,KAAK,gBAAgBD,IACtC;AAAA,IACL,IAAAb;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAKa,EAAI;AAAA,MACT,SAASd,EAAI;AAAA,IAAA;AAAA,IAEf,WAAAE;AAAA,EAAA,IAKA,gBAAgBY,IACX;AAAA,IACL,IAAAb;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,KAAKa,EAAI;AAAA,MACT,MAAMA,EAAI,QAAQ;AAAA,MAClB,UAAUC;AAAA,IAAA;AAAA,IAEZ,WAAAb;AAAA,EAAA,IAIG;AACT;AAMA,SAASU,EAAgBI,GAAuD;AAC9E,SAAO;AAAA,IACL,OAAOA,EAAQ,SAAS,CAAC,GAAG;AAAA,IAC5B,OAAOA,EAAQ,SAAS;AAAA,IACxB,UAAUA,EAAQ,YAAYA,EAAQ;AAAA,IACtC,SAASE,EAAeF,EAAQ,OAAO;AAAA,EAAA;AAE3C;AAMO,SAASE,EACdG,GACiB;AACjB,SAAI,CAACA,KAAWA,EAAQ,WAAW,IAAU,CAAA,IAEtCA,EAAQ,IAAI,CAACC,MAAuB;AACzC,UAAMC,KAAS,WAAWD,IAAMA,EAAI,QAAQ,WAAc,OAAOA,EAAI,SAAS,EAAE;AAEhF,YAAQA,EAAI,MAAA;AAAA,MACV,KAAK;AAAA,MACL,KAAK;AACH,eAAO,EAAE,OAAAC,GAAO,KAAK,OAAOD,EAAI,SAAS,EAAE,EAAA;AAAA,MAE7C,KAAK;AACH,eAAO,EAAE,OAAAC,GAAO,KAAK,OAAOD,EAAI,SAAS,EAAE,EAAA;AAAA,MAK7C;AACE,eAAO,EAAE,OAAAC,GAAO,OAAO,OAAOD,EAAI,SAASC,CAAK,EAAA;AAAA,IAAE;AAAA,EAExD,CAAC;AACH;AAMA,SAASlB,EAAoBL,GAA+B;AAC1D,QAAMwB,IAAUxB,EAAI,kBAAkB;AACtC,SAAI,CAACwB,KAAWA,EAAQ,WAAW,IAAU,CAAA,IAEtCA,EAAQ,IAAI,CAACC,MAAqB;AACvC,UAAMF,KAAS,WAAWE,IAAIA,EAAE,QAAQ,WAAc,OAAOA,EAAE,SAAS,EAAE;AAC1E,WAAIA,EAAE,SAAS,YACN,EAAE,OAAAF,GAAO,KAAK,OAAOE,EAAE,SAAS,EAAE,EAAA,IAEpC,EAAE,OAAAF,GAAO,OAAO,OAAOE,EAAE,SAASF,CAAK,EAAA;AAAA,EAChD,CAAC;AACH;AAkBA,SAASG,EACPC,GACAC,GACAP,GACAQ,GACA;AACA,MAAKF;AACL,eAAWG,KAAMH;AACf,cAAQG,EAAG,MAAA;AAAA,QACT,KAAK;AACH,UAAIA,EAAG,QAAMF,EAAM,KAAKE,EAAG,IAAI;AAC/B;AAAA,QACF,KAAK;AACH,UAAIA,EAAG,OAAKD,EAAQC,EAAG,GAAG;AAC1B;AAAA,QACF,KAAK;AACH,UAAIA,EAAG,WAASC,EAAmBD,EAAG,SAAST,CAAO;AACtD;AAAA,QACF,KAAK;AACH,UAAAK,EAAqBI,EAAG,OAAOF,GAAOP,GAASQ,CAAO;AACtD;AAAA,QACF,KAAK;AACH,qBAAWG,KAAOF,EAAG,WAAW,CAAA;AAC9B,YAAAJ,EAAqBM,EAAI,OAAOJ,GAAOP,GAASQ,CAAO;AAEzD;AAAA,QACF,KAAK;AACH,UAAAH,EAAqBI,EAAG,OAAOF,GAAOP,GAASQ,CAAO;AACtD;AAAA,MAAA;AAGR;AAGA,SAASI,EAAsBjB,GAAkC;AAC/D,QAAMY,IAAkB,CAAA;AACxB,MAAIM;AACJ,QAAMb,IAA2B,CAAA;AAEjC,SAAAK;AAAA,IACEV,EAAQ;AAAA,IACRY;AAAA,IACAP;AAAA,IACA,CAACc,MAAQ;AAAE,MAAAD,IAAQA,KAASC;AAAA,IAAK;AAAA,EAAA,GAG/B,MAAM,QAAQnB,EAAQ,OAAO,KAC/Be,EAAmBf,EAAQ,SAAgDK,CAAO,GAG7E,EAAE,OAAAO,GAAO,OAAAM,GAAO,SAAAb,EAAA;AACzB;AAKA,SAASV,EACPK,GACyB;AACzB,QAAM,EAAE,OAAAY,GAAO,OAAAM,GAAO,SAAAb,EAAA,IAAYY,EAAsBjB,CAAO;AAC/D,SAAO;AAAA,IACL,OAAAkB;AAAA,IACA,OAAON,EAAM,CAAC,KAAK;AAAA,IACnB,UAAUA,EAAM,MAAM,CAAC,EAAE,KAAK;AAAA,CAAI;AAAA,IAClC,SAAAP;AAAA,EAAA;AAEJ;AAEA,SAASJ,EACPD,GACAf,GACAC,GACiB;AACjB,QAAM,EAAE,OAAA0B,GAAO,OAAAM,GAAO,SAAAb,EAAA,IAAYY,EAAsBjB,CAAO,GAGzDoB,IACHpB,EAAQ,gBACRA,EAAQ,SACTY,EAAM,KAAK;AAAA,CAAI;AAGjB,SAAIM,IACK;AAAA,IACL,IAAAjC;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,OAAAiC;AAAA,MACA,OAAON,EAAM,CAAC,KAAK;AAAA,MACnB,UAAUA,EAAM,MAAM,CAAC,EAAE,KAAK;AAAA,CAAI;AAAA,MAClC,SAAAP;AAAA,IAAA;AAAA,IAEF,WAAAnB;AAAA,EAAA,IAKAmB,EAAQ,SAAS,IACZ;AAAA,IACL,IAAApB;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,MAAMmC,KAAY;AAAA,MAClB,SAAAf;AAAA,IAAA;AAAA,IAEF,WAAAnB;AAAA,EAAA,IAKG;AAAA,IACL,IAAAD;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,EAAE,MAAMmC,KAAY,kBAAA;AAAA,IAC1B,WAAAlC;AAAA,EAAA;AAEJ;AAEA,SAAS6B,EACPP,GACAa,GACA;AACA,aAAWZ,KAAKD,GAAS;AACvB,UAAMD,IAAQE,EAAE,SAAS;AACzB,IAAIA,EAAE,SAAS,oBAAoBA,EAAE,MACnCY,EAAI,KAAK,EAAE,OAAAd,GAAO,KAAKE,EAAE,KAAK,IACrBA,EAAE,SAAS,kBACpBY,EAAI,KAAK,EAAE,OAAAd,GAAO,OAAO,OAAOE,EAAE,QAAS,WAAWA,EAAE,OAAOF,EAAA,CAAO,IAEtEc,EAAI,KAAK,EAAE,OAAAd,GAAO,OAAOA,GAAO;AAAA,EAEpC;AACF;AAMA,SAASJ,EACPH,GACAf,GACAC,GACiB;AACjB,QAAMoC,IAAkB,CAAA;AAGxB,MAFItB,EAAQ,SAAOsB,EAAM,KAAK,KAAKtB,EAAQ,KAAK,IAAI,GAEhDA,EAAQ;AACV,eAAWuB,KAAQvB,EAAQ;AACzB,MAAAsB,EAAM,KAAK,GAAGC,EAAK,GAAG,KAAKA,EAAK,KAAK,EAAE;AAI3C,MAAIvB,EAAQ;AACV,eAAWwB,KAAQxB,EAAQ,OAAO;AAChC,YAAMyB,IAAQD,EAAK,QAAQ,MAAMA,EAAK,KAAK,KAAK;AAChD,MAAAF,EAAM,KAAK,KAAKE,EAAK,SAAS,MAAM,GAAGC,CAAK,EAAE;AAAA,IAChD;AAGF,SAAIzB,EAAQ,OAAKsB,EAAM,KAAK,QAAQtB,EAAQ,GAAG,EAAE,GAC7CA,EAAQ,SAAOsB,EAAM,KAAK,YAAYtB,EAAQ,KAAK,IAAI,GAEpD;AAAA,IACL,IAAAf;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,EAAE,MAAMqC,EAAM,KAAK;AAAA,CAAI,EAAA;AAAA,IAC7B,WAAApC;AAAA,EAAA;AAEJ;ACzbA,MAAMwC,IAAc,6BACdC,IAAmB;AAWzB,SAASC,IAA4B;AACjC,MAAI;AACA,UAAMC,IAAS,aAAa,QAAQH,CAAW;AAC/C,QAAIG,EAAQ,QAAOA;AAAA,EACvB,QAAQ;AAAA,EAER;AACA,QAAM5C,IACF,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,IACtC,KAAK,SAAS,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AAC1C,MAAI;AACA,iBAAa,QAAQyC,GAAazC,CAAE;AAAA,EACxC,QAAQ;AAAA,EAER;AACA,SAAOA;AACX;AAGA,SAAS6C,EAAeC,GAA8B;AAClD,MAAI;AACA,UAAMC,IAAU,KAAK,MAAM,KAAKD,EAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AACpD,WAAO,OAAOC,EAAQ,OAAQ,WAAWA,EAAQ,MAAM,MAAO;AAAA,EAClE,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AAEA,eAAeC,EACXC,GACAnD,GACkD;AAClD,QAAMoD,IAAM,MAAM;AAAA,IACd;AAAA,IACA;AAAA,MACI,QAAQ;AAAA,MACR,SAAS;AAAA,QACL,eAAe,UAAUD,CAAM;AAAA,QAC/B,gBAAgB;AAAA,MAAA;AAAA,MAEpB,MAAM,KAAK,UAAU,EAAE,MAAM,EAAE,IAAInD,GAAQ,MAAMA,IAAO,CAAG;AAAA,IAAA;AAAA,EAC/D;AAEJ,MAAI,CAACoD,EAAI;AACL,UAAM,IAAI,MAAM,kCAAkCA,EAAI,MAAM,EAAE;AAElE,QAAMC,IAAQ,MAAMD,EAAI,KAAA;AAIxB,SAAO,EAAE,OAAOC,EAAK,OAAO,gBAAgBA,EAAK,eAAA;AACrD;AAEA,eAAeC,EACXlB,GACoE;AACpE,QAAMgB,IAAM,MAAM,MAAMhB,GAAK,EAAE,QAAQ,QAAQ;AAC/C,MAAI,CAACgB,EAAI;AACL,UAAM,IAAI,MAAM,2BAA2BA,EAAI,MAAM,EAAE;AAE3D,SAAQ,MAAMA,EAAI,KAAA;AAKtB;AAGA,eAAeG,EACXC,GACAC,GACkD;AAElD,QAAML,IAAM,MAAM,MAAM,GADXK,KAAU,mDACQ,mBAAmB;AAAA,IAC9C,QAAQ;AAAA,IACR,SAAS,EAAE,eAAe,UAAUD,CAAY,GAAA;AAAA,EAAG,CACtD;AACD,MAAI,CAACJ,EAAI;AACL,UAAM,IAAI,MAAM,yBAAyBA,EAAI,MAAM,EAAE;AAEzD,SAAQ,MAAMA,EAAI,KAAA;AACtB;AASO,MAAMM,EAA0C;AAAA,EAiCnD,YAAYC,GAAqC;AAhCjD,SAAS,OAAO,cAChB,KAAS,mBAAmB,IAQ5B,KAAQ,aAAoC,MAE5C,KAAQ,iBAAwC,MAChD,KAAQ,iBAAwC,MAChD,KAAQ,oBAA8C,MACtD,KAAQ,gBAAsC,MAC9C,KAAQ,uBAAoD,MAE5D,KAAQ,cAAqC,MAC7C,KAAQ,gBAAuC,MAC/C,KAAQ,gBAAsD,MAC9D,KAAQ,eAAqD,MAE7D,KAAQ,aAAuB,CAAA,GAE/B,KAAQ,qBAAqB,IAE7B,KAAQ,eAAoC,MAI5C,KAAQ,gBAAgB,IAGpB,KAAK,UAAUA;AAAA,EACnB;AAAA,EAEA,WAAWC,GAA2B;AAClC,SAAK,aAAaA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,gBAAgBC,GAAcC,GAA6B;AACvD,SAAK,QAAQ,kBAAkB,CAAA,GAC/B,KAAK,QAAQ,cAAcD,CAAI,IAAIC;AAAA,EACvC;AAAA;AAAA,EAGA,mBAAmBD,GAAuB;AACtC,WAAK,KAAK,QAAQ,gBAAgBA,CAAI,KACtC,OAAO,KAAK,QAAQ,cAAcA,CAAI,GAC/B,MAFyC;AAAA,EAGpD;AAAA;AAAA,EAGA,gBAAgBA,GAAuB;AACnC,WAAO,CAAC,CAAC,KAAK,QAAQ,gBAAgBA,CAAI;AAAA,EAC9C;AAAA;AAAA,EAGA,uBAAiC;AAC7B,WAAO,OAAO,KAAK,KAAK,QAAQ,iBAAiB,CAAA,CAAE;AAAA,EACvD;AAAA,EAEA,MAAM,UAAyB;AAC3B,SAAK,SAAS,KAAK,QAAQ,UAAUhB,EAAA,GACrC,KAAK,WAAW,KAAK,QAAQ;AAG7B,QAAIkB,IAAa;AACjB,QAAI,KAAK,QAAQ,oBAAoB;AACjC,YAAMC,IAAY,KAAK,0BAAA;AACvB,UAAIA;AACA,YAAI;AACA,gBAAMC,IAAY,MAAMV;AAAA,YACpBS,EAAU;AAAA,YACV,KAAK,QAAQ;AAAA,UAAA;AAEjB,eAAK,QAAQC,EAAU,OACvB,KAAK,iBAAiBD,EAAU,gBAChC,KAAK,YAAYA,EAAU,WAC3B,KAAK,SAASA,EAAU,QACxBD,IAAa;AAAA,QACjB,QAAQ;AAEJ,eAAK,2BAAA;AAAA,QACT;AAAA,IAER;AAGA,QAAI,CAACA;AACD,UAAI,KAAK,QAAQ,mBAAmB;AAChC,cAAMxD,IAAS,MAAM+C;AAAA,UACjB,KAAK,QAAQ;AAAA,QAAA;AAEjB,aAAK,QAAQ/C,EAAO,OAChBA,EAAO,mBACP,KAAK,iBAAiBA,EAAO,iBAC7BA,EAAO,WAAQ,KAAK,SAASA,EAAO;AAAA,MAC5C,WAAW,KAAK,QAAQ;AACpB,aAAK,QAAQ,KAAK,QAAQ;AAAA,eACnB,KAAK,QAAQ,QAAQ;AAC5B,cAAMA,IAAS,MAAM2C;AAAA,UACjB,KAAK,QAAQ;AAAA,UACb,KAAK;AAAA,QAAA;AAET,aAAK,QAAQ3C,EAAO,OACpB,KAAK,iBAAiBA,EAAO;AAAA,MACjC;AACI,cAAM,IAAI;AAAA,UACN;AAAA,QAAA;AAMZ,SAAK,qBAAA,GAGL,KAAK,aAAa,IAAI2D,EAAW;AAAA,MAC7B,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK,QAAQ;AAAA,MACrB,GAAIH,IACE;AAAA,QACI,gBAAgB,KAAK;AAAA,QACrB,WAAW,KAAK;AAAA,MAAA,IAEpB,CAAA;AAAA,IAAC,CACV,GAEGA,MACA,KAAK,qBAAqB,IAC1B,KAAK,gBAAgB;AAIzB,UAAMI,IAAQ,IAAI,QAAc,CAACC,MAAY;AACzC,WAAK,eAAeA;AAAA,IACxB,CAAC;AAED,SAAK,eAAeL,CAAU,GAE9B,MAAMI,GACN,KAAK,iBAAA,GAED,KAAK,QAAQ,sBACb,KAAK,oBAAA;AAAA,EAEb;AAAA,EAEA,MAAM,aAA4B;AAC9B,SAAK,aAAa,YAAA,GAClB,KAAK,cAAc,MACnB,KAAK,eAAe,YAAA,GACpB,KAAK,gBAAgB,MACrB,KAAK,mBAAA,GACL,KAAK,kBAAA;AAEL,QAAI;AACA,WAAK,YAAY,IAAA;AAAA,IACrB,QAAQ;AAAA,IAER;AAEA,SAAK,iBAAiB,MACtB,KAAK,iBAAiB,MACtB,KAAK,oBAAoB,MACzB,KAAK,gBAAgB,MACrB,KAAK,uBAAuB;AAAA,EAChC;AAAA;AAAA,EAGA,oBAA0B;AACtB,SAAK,YAAY,QACjB,KAAK,2BAAA;AAAA,EACT;AAAA,EAEA,MAAM,YAAYE,GAAyC;AACvD,gBAAK,WAAW,KAAKA,EAAQ,EAAE,GAE/B,KAAK,uBAAuBA,EAAQ,IAAI,MAAM,GACvC,IAAI,QAAc,CAACD,GAASE,MAAW;AAC1C,WAAK,WACA,aAAa;AAAA,QACV,MAAM;AAAA,QACN,MAAM;AAAA,UACF,IAAI,KAAK;AAAA,UACT,MAAM,KAAK,YAAY,KAAK;AAAA,QAAA;AAAA,QAEhC,MAAOD,EAAQ,KAA2B,QAAQ;AAAA,QAClD,cAAc,EAAE,IAAI,KAAK,eAAA;AAAA,QACzB,WAAW;AAAA,QACX,GAAI,KAAK,QAAQ,SACX,EAAE,QAAQ,KAAK,QAAQ,OAAA,IACvB,CAAA;AAAA,QACN,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,QACtB,IAAIA,EAAQ;AAAA,MAAA,CACf,EACA,UAAU;AAAA,QACP,MAAM,MAAMD,EAAA;AAAA,QACZ,OAAO,CAACG,MAAiBD,EAAOC,CAAG;AAAA,MAAA,CACtC;AAAA,IACT,CAAC;AAAA,EACL;AAAA,EAEA,MAAM,SAASC,GAA2B;AAItC,UAAMpC,IAAM,GAFR,KAAK,QAAQ,UACb,mDACiB,kBAAkB,KAAK,cAAc,kBAAkB,mBAAmB,KAAK,MAAM,CAAC,IAErGqC,IAAW,IAAI,SAAA;AACrB,IAAAA,EAAS,OAAO,QAAQD,GAAMA,EAAK,IAAI;AAEvC,UAAMpB,IAAM,MAAM,MAAMhB,GAAK;AAAA,MACzB,QAAQ;AAAA,MACR,SAAS,EAAE,eAAe,UAAU,KAAK,KAAK,GAAA;AAAA,MAC9C,MAAMqC;AAAA,IAAA,CACT;AAED,QAAI,CAACrB,EAAI;AACL,YAAM,IAAI,MAAM,kCAAkCA,EAAI,MAAM,EAAE;AAAA,EAEtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,WAAWH,GAAuC;AACpD,UAAMyB,IACF,OAAOzB,EAAQ,QAAS,WAClBA,EAAQ,OACRA,EAAQ,SAAS,SACf,OAAOA,EAAQ,IAAI,IACnB,GACN0B,IAAO,OAAO,SAASD,CAAO,IAAIA,IAAU;AAElD,WAAO,IAAI,QAAc,CAACN,GAASE,MAAW;AAC1C,WAAK,WACA,aAAa;AAAA,QACV,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM,EAAE,IAAI,KAAK,QAAQ,MAAM,KAAK,OAAA;AAAA,QACpC,OAAO;AAAA,UACH,QAAQrB,EAAQ;AAAA,UAChB,SAASA,EAAQ,WAAW;AAAA,UAC5B,MAAA0B;AAAA,QAAA;AAAA,MACJ,CACH,EACA,UAAU;AAAA,QACP,MAAM,MAAMP,EAAA;AAAA,QACZ,OAAO,CAACG,MAAiBD,EAAOC,CAAG;AAAA,MAAA,CACtC;AAAA,IACT,CAAC;AAAA,EACL;AAAA,EAEA,MAAM,aACFK,GACAC,GACa;AAKb,UAAMC,IAHM,KAAK,YAAY,SACxB,OAAA,EACA,KAAK,CAACC,MAAMA,EAAE,OAAOH,CAAS,GAE1B,MAAM,aACZ;AAEH,QAAI,CAACE,GAAe;AAChB,cAAQ;AAAA,QACJ;AAAA,QACAF;AAAA,MAAA;AAEJ;AAAA,IACJ;AAGA,UAAMI,IAAeH,MAAa,SAAS,IAAI;AAE/C,WAAO,IAAI,QAAc,CAACT,GAASE,MAAW;AAC1C,WAAK,WACA,aAAa;AAAA,QACV,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM,EAAE,IAAI,KAAK,QAAQ,MAAM,KAAK,OAAA;AAAA,QACpC,OAAO,EAAE,eAAAQ,GAAe,cAAAE,EAAA;AAAA,MAAa,CACxC,EACA,UAAU;AAAA,QACP,MAAM,MAAMZ,EAAA;AAAA,QACZ,OAAO,CAACG,MAAiBD,EAAOC,CAAG;AAAA,MAAA,CACtC;AAAA,IACT,CAAC;AAAA,EACL;AAAA,EAEA,MAAM,YAAYU,GAAyC;AACvD,UAAMxB,IACF,KAAK,QAAQ,UACb,qDACErB,IAAM6C,IACN,GAAGxB,CAAM,kBAAkB,KAAK,cAAc,yBAAyB,mBAAmBwB,CAAM,CAAC,KACjG,GAAGxB,CAAM,kBAAkB,KAAK,cAAc,eAE9CL,IAAM,MAAM,MAAMhB,GAAK;AAAA,MACzB,SAAS,EAAE,eAAe,UAAU,KAAK,KAAK,GAAA;AAAA,IAAG,CACpD;AAED,QAAI,CAACgB,EAAI;AACL,YAAM,IAAI,MAAM,oCAAoCA,EAAI,MAAM,EAAE;AAGpE,UAAMC,IAAQ,MAAMD,EAAI,KAAA,GAKlB8B,IAA8B,CAAA;AACpC,eAAWnF,KAAYsD,EAAK,YAAY;AAGpC,UACItD,EAAS,KAAK,OAAO,KAAK,UAC1BA,EAAS,SAAS,WACpB;AACE,cAAME,IAAMF;AACZ,QAAIE,EAAI,QACJiF,EAAS,KAAK;AAAA,UACV,IACInF,EAAS,MACT,MAAM,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,UAC9D,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM,EAAE,MAAME,EAAI,KAAA;AAAA,UAClB,WAAWF,EAAS,YACd,IAAI,KAAKA,EAAS,SAAS,EAAE,YAC7B,KAAK,IAAA;AAAA,QAAI,CAClB;AAEL;AAAA,MACJ;AAEA,YAAMQ,IAAST,EAAqBC,GAAU,KAAK,MAAM;AACzD,MAAIQ,MAAW,QAAQA,MAAWpB,KAC9B+F,EAAS,KAAK3E,CAAM;AAAA,IAE5B;AAEA,WAAO;AAAA,MACH,UAAA2E;AAAA,MACA,SAAS;AAAA,MACT,QAAQ7B,EAAK;AAAA,IAAA;AAAA,EAErB;AAAA,EAEA,UAAU8B,GAAgC;AACtC,SAAK,iBAAiBA;AAAA,EAC1B;AAAA,EAEA,UAAUA,GAAgC;AACtC,SAAK,iBAAiBA;AAAA,EAC1B;AAAA,EAEA,aAAaA,GAAmC;AAC5C,SAAK,oBAAoBA;AAAA,EAC7B;AAAA,EAEA,SAASA,GAA+B;AACpC,SAAK,gBAAgBA;AAAA,EACzB;AAAA,EAEA,gBAAgBA,GAAsC;AAClD,SAAK,uBAAuBA;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,eAAeC,GAA0B;AAC7C,SAAK,gBAAgB,KAAK,WAAW,kBAAkB;AAAA,MACnD,CAACC,MAA6B;AAC1B,gBAAQA,GAAA;AAAA,UACJ,KAAKC,EAAiB;AAClB,iBAAK,cAAA,GAEDF,KAAmB,KAAK,iBACxB,KAAK,aAAA,GACL,KAAK,eAAe;AAExB;AAAA,UACJ,KAAKE,EAAiB;AAClB,iBAAK,mBAAA;AACL;AAAA,UACJ,KAAKA,EAAiB;AAClB,YAAI,KAAK,QAAQ,sBACb,KAAK,2BAAA,GAET,KAAK,oBAAoB,mBAAmB;AAC5C;AAAA,UACJ,KAAKA,EAAiB;AAClB,iBAAK,oBAAoB,kBAAkB;AAC3C;AAAA,QAAA;AAAA,MAEZ;AAAA,IAAA,GAGJ,KAAK,cAAc,KAAK,WAAW,UAAU,UAAU,CAACvF,MAAa;AACjE,UAAI;AAQA,YANIA,EAAS,OAAI,KAAK,YAAYA,EAAS,KACvC,CAAC,KAAK,kBAAkBA,EAAS,cAAc,OAC/C,KAAK,iBAAiBA,EAAS,aAAa,KAI5CA,EAAS,KAAK,OAAO,KAAK,QAAQ;AAElC,cAAIA,EAAS,SAAS,WAAW;AAC7B,kBAAMwF,IAAY,KAAK,WAAW,MAAA;AAClC,YAAIA,KACA,KAAK,uBAAuBA,GAAW,MAAM;AAAA,UAErD;AACA;AAAA,QACJ;AAGA,YAAIxF,EAAS,SAAS,WAAWA,EAAS,MAAM;AAE5C,cACIA,EAAS,SAAS,2BAClBA,EAAS,OACX;AACE,kBAAMyF,IAAMzF,EAAS;AAIrB,YAAIyF,EAAI,iBACJ,KAAK;AAAA,cACDA,EAAI;AAAA,cACJA,EAAI;AAAA,YAAA;AAAA,UAGhB;AAGA,gBAAM1B,IAAU,KAAK,QAAQ,gBAAgB/D,EAAS,IAAI;AAC1D,UAAI+D,KACAA,EAAQ,KAAK,mBAAmB/D,CAAQ,CAAC;AAE7C;AAAA,QACJ;AAEA,cAAMQ,IAAST,EAAqBC,GAAU,KAAK,MAAM;AAEzD,YAAIQ,MAAWpB,GAAiB;AAC5B,eAAK,aAAA;AACL;AAAA,QACJ;AAEA,QAAIoB,MAAW,SAEX,KAAK,mBAAA,GACL,KAAK,gBAAgB,EAAK,GAGtB,KAAK,iBACL,KAAK,aAAA,GACL,KAAK,eAAe,OAGxB,KAAK,iBAAiBA,CAAM,GAGxB,KAAK,QAAQ,sBACb,KAAK,oBAAA;AAAA,MAGjB,SAASgE,GAAK;AACV,gBAAQ;AAAA,UACJ;AAAA,UACAA;AAAA,QAAA;AAAA,MAER;AAAA,IACJ,CAAC;AAAA,EACL;AAAA;AAAA,EAGQ,mBAAmBxE,GAAyC;AAChE,UAAM0F,IAAO,EAAE,IAAI,KAAK,QAAQ,MAAM,KAAK,YAAY,KAAK,OAAA;AAC5D,WAAO;AAAA,MACH,UAAA1F;AAAA,MACA,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK,YAAY,KAAK;AAAA,MAChC,WAAW,CAAC8D,GAAc6B,MAAoB;AAC1C,aAAK,WACA,aAAa;AAAA,UACV,MAAM;AAAA,UACN,MAAA7B;AAAA,UACA,MAAA4B;AAAA,UACA,GAAI,KAAK,QAAQ,SACX,EAAE,QAAQ,KAAK,QAAQ,OAAA,IACvB,CAAA;AAAA,UACN,OAAAC;AAAA,QAAA,CACH,EACA,UAAA;AAAA,MACT;AAAA,MACA,SAAS,KAAK;AAAA,IAAA;AAAA,EAEtB;AAAA;AAAA,EAGQ,gBAAgB;AACpB,UAAMC,IAAS,KAAK,QAAQ,QACtBF,IAAO,EAAE,IAAI,KAAK,QAAQ,MAAM,KAAK,YAAY,KAAK,OAAA;AAK5D,QAHK,KAAK,oBAGN,KAAK,eAAe;AACpB,WAAK,gBAAgB,IACrB,KAAK,qBAAqB,IAC1B,KAAK,WACA,aAAa;AAAA,QACV,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAAA;AAAA,QACA,GAAIE,IAAS,EAAE,QAAAA,EAAA,IAAW,CAAA;AAAA,QAC1B,OAAO,EAAE,GAAIA,IAAS,EAAE,UAAUA,EAAA,IAAW,CAAA,EAAC;AAAA,MAAG,CACpD,EACA,UAAA;AACL;AAAA,IACJ;AACA,SAAK,WACA,aAAa;AAAA,MACV,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAAF;AAAA,MACA,GAAIE,IAAS,EAAE,QAAAA,EAAA,IAAW,CAAA;AAAA,MAC1B,OAAO;AAAA,QACH,GAAIA,IAAS,EAAE,UAAUA,EAAA,IAAW,CAAA;AAAA,QACpC,GAAG,KAAK,QAAQ;AAAA,MAAA;AAAA,IACpB,CACH,EACA,UAAA;AAAA,EACT;AAAA;AAAA,EAGQ,sBACJb,GACAE,GACF;AACE,UAAME,IAAW,KAAK,YAAY,SAAS,OAAA;AAC3C,QAAI,CAACA,EAAU;AACf,UAAMjF,IAAMiF,EAAS;AAAA,MACjB,CAACH,MACIA,EAAE,MAAM,aACH,kBAAkBD;AAAA,IAAA;AAEhC,IAAI7E,KACA,KAAK,WAAY,SAAS,OAAOA,EAAI,IAAI;AAAA,MACrC,MAAM,EAAE,GAAGA,EAAI,MAAM,kBAAkB,IAAM,cAAA+E,EAAA;AAAA,IAAa,CAC7D;AAAA,EAET;AAAA,EAEQ,eAAe;AAGnB,QAFA,KAAK,mBAAA,GACL,KAAK,gBAAgB,EAAI,GACrB,KAAK,QAAQ;AAEb;AAEJ,UAAMY,IAAK,KAAK,QAAQ,mBAAmB;AAC3C,SAAK,gBAAgB,WAAW,MAAM;AAClC,WAAK,gBAAgB,EAAK,GAC1B,KAAK,gBAAgB;AAAA,IACzB,GAAGA,CAAE;AAAA,EACT;AAAA,EAEQ,qBAAqB;AACzB,IAAI,KAAK,kBAAkB,SACvB,aAAa,KAAK,aAAa,GAC/B,KAAK,gBAAgB;AAAA,EAE7B;AAAA;AAAA;AAAA,EAKQ,uBAAuB;AAC3B,SAAK,kBAAA;AACL,UAAMC,IAAS9C,EAAe,KAAK,KAAK;AACxC,QAAI,CAAC8C,EAAQ;AAEb,UAAMC,IAAQD,IAAS,KAAK,IAAA,IAAQ;AACpC,QAAIC,KAAS,GAAG;AAEZ,WAAK,gBAAA;AACL;AAAA,IACJ;AACA,SAAK,eAAe,WAAW,MAAM,KAAK,gBAAA,GAAmBA,CAAK;AAAA,EACtE;AAAA;AAAA,EAGA,MAAc,kBAAkB;AAC5B,QAAI;AACA,YAAMvF,IAAS,MAAMgD;AAAA,QACjB,KAAK;AAAA,QACL,KAAK,QAAQ;AAAA,MAAA;AAEjB,WAAK,QAAQhD,EAAO,OACpB,KAAK,qBAAA,GACD,KAAK,QAAQ,sBACb,KAAK,oBAAA;AAAA,IAEb,SAASgE,GAAK;AACV,cAAQ,KAAK,+CAA+CA,CAAG;AAAA,IACnE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,qBAAqB;AAC/B,QAAI;AACA,YAAMhE,IAAS,MAAMgD;AAAA,QACjB,KAAK;AAAA,QACL,KAAK,QAAQ;AAAA,MAAA;AAEjB,WAAK,QAAQhD,EAAO,OACpB,KAAK,qBAAA;AAAA,IACT,QAAQ;AACJ,MAAI,KAAK,QAAQ,sBACb,KAAK,2BAAA,GAET,KAAK,oBAAoB,kCAAkC;AAC3D;AAAA,IACJ;AAGA,SAAK,aAAa,YAAA,GAClB,KAAK,eAAe,YAAA,GACpB,KAAK,mBAAA;AACL,QAAI;AACA,WAAK,WAAW,IAAA;AAAA,IACpB,QAAQ;AAAA,IAER;AAGA,SAAK,aAAa,IAAI2D,EAAW;AAAA,MAC7B,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK,QAAQ;AAAA,MACrB,gBAAgB,KAAK;AAAA,MACrB,WAAW,KAAK;AAAA,IAAA,CACnB,GAED,KAAK,eAAe,EAAI,GAEpB,KAAK,QAAQ,sBACb,KAAK,oBAAA;AAAA,EAEb;AAAA,EAEQ,oBAAoB;AACxB,IAAI,KAAK,iBAAiB,SACtB,aAAa,KAAK,YAAY,GAC9B,KAAK,eAAe;AAAA,EAE5B;AAAA;AAAA,EAIQ,sBAAsB;AAC1B,QAAI,GAAC,KAAK,kBAAkB,CAAC,KAAK;AAClC,UAAI;AACA,cAAMb,IAA8B;AAAA,UAChC,gBAAgB,KAAK;AAAA,UACrB,OAAO,KAAK;AAAA,UACZ,WAAW,KAAK;AAAA,UAChB,QAAQ,KAAK;AAAA,QAAA;AAEjB,qBAAa,QAAQT,GAAkB,KAAK,UAAUS,CAAI,CAAC;AAAA,MAC/D,QAAQ;AAAA,MAER;AAAA,EACJ;AAAA,EAEQ,4BAA0D;AAC9D,QAAI;AACA,YAAM0C,IAAM,aAAa,QAAQnD,CAAgB;AACjD,aAAKmD,IACE,KAAK,MAAMA,CAAG,IADJ;AAAA,IAErB,QAAQ;AACJ,aAAO;AAAA,IACX;AAAA,EACJ;AAAA,EAEQ,6BAA6B;AACjC,QAAI;AACA,mBAAa,WAAWnD,CAAgB;AAAA,IAC5C,QAAQ;AAAA,IAER;AAAA,EACJ;AACJ;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chativa/connector-directline",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Chativa DirectLine connector — Azure Bot Framework DirectLine v3 adapter.",
5
5
  "author": "Hamza Agar",
6
6
  "license": "MIT",
@@ -48,7 +48,7 @@
48
48
  "vite": "^7.0.3",
49
49
  "vite-plugin-dts": "^4.5.4",
50
50
  "vitest": "^4.0.18",
51
- "@chativa/core": "0.6.0"
51
+ "@chativa/core": "0.7.1"
52
52
  },
53
53
  "scripts": {
54
54
  "build": "vite build && vite build --config vite.config.cdn.ts",