@tangle-network/agent-integrations 0.65.1 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -392,13 +392,13 @@ function isRecord(value) {
392
392
  }
393
393
  //#endregion
394
394
  //#region src/conversation-events/linq-whatsapp.ts
395
- function object$1(value) {
395
+ function object$2(value) {
396
396
  return value !== null && typeof value === "object" && !Array.isArray(value);
397
397
  }
398
398
  function id(value) {
399
399
  return typeof value === "string" && value.length > 0 && value.length <= 256 && !/[\u0000-\u001f\u007f]/.test(value);
400
400
  }
401
- const invalid$3 = (message) => ({
401
+ const invalid$4 = (message) => ({
402
402
  ok: false,
403
403
  code: "invalid_payload",
404
404
  message
@@ -436,25 +436,25 @@ function mediaPart(part) {
436
436
  * Keep that customer opaque; never mislabel message.from (our number) as the sender. */
437
437
  function normalizeLinqWhatsappConversation(input) {
438
438
  const value = input.payload;
439
- if (!object$1(value) || input.type !== `linq-whatsapp.${value.type}`) return invalid$3("Event type does not match the provider envelope");
439
+ if (!object$2(value) || input.type !== `linq-whatsapp.${value.type}`) return invalid$4("Event type does not match the provider envelope");
440
440
  if (value.type !== "message.received") return {
441
441
  ok: false,
442
442
  code: "unsupported_event",
443
443
  message: "Not an incoming message"
444
444
  };
445
- if (!object$1(value.data) || !object$1(value.data.message)) return invalid$3("Read the chat journal to hydrate this historical event");
445
+ if (!object$2(value.data) || !object$2(value.data.message)) return invalid$4("Read the chat journal to hydrate this historical event");
446
446
  const message = value.data.message;
447
- if (!id(value.id) || !id(message.id) || !id(message.chat_id) || !id(message.from) || message.direction !== "inbound") return invalid$3("Incoming message requires a stable identity, conversation and owned destination");
448
- if (value.data.chat_id !== void 0 && value.data.chat_id !== message.chat_id) return invalid$3("Chat identity mismatch");
449
- if (!Array.isArray(message.parts) || !message.parts.length || message.parts.length > 50) return invalid$3("Invalid message parts");
447
+ if (!id(value.id) || !id(message.id) || !id(message.chat_id) || !id(message.from) || message.direction !== "inbound") return invalid$4("Incoming message requires a stable identity, conversation and owned destination");
448
+ if (value.data.chat_id !== void 0 && value.data.chat_id !== message.chat_id) return invalid$4("Chat identity mismatch");
449
+ if (!Array.isArray(message.parts) || !message.parts.length || message.parts.length > 50) return invalid$4("Invalid message parts");
450
450
  const text = [];
451
451
  const attachments = [];
452
452
  let historyOnly = false;
453
453
  for (const part of message.parts) {
454
- if (!object$1(part)) return invalid$3("Invalid message part");
454
+ if (!object$2(part)) return invalid$4("Invalid message part");
455
455
  if (part.type === "media") {
456
456
  const media = mediaPart(part);
457
- if (!media) return invalid$3("Invalid media attachment");
457
+ if (!media) return invalid$4("Invalid media attachment");
458
458
  attachments.push(media.attachment);
459
459
  if (media.caption) text.push(media.caption);
460
460
  if (!media.attachment.url) historyOnly = true;
@@ -466,7 +466,7 @@ function normalizeLinqWhatsappConversation(input) {
466
466
  };
467
467
  }
468
468
  const occurredAt = typeof message.created_at === "string" ? Date.parse(message.created_at) : NaN;
469
- if (!Number.isSafeInteger(occurredAt) || occurredAt < 0) return invalid$3("Invalid message timestamp");
469
+ if (!Number.isSafeInteger(occurredAt) || occurredAt < 0) return invalid$4("Invalid message timestamp");
470
470
  return {
471
471
  ok: true,
472
472
  event: {
@@ -514,7 +514,7 @@ function timestamp(value) {
514
514
  function phone$1(value) {
515
515
  return typeof value === "string" && /^\+[1-9]\d{6,14}$/.test(value);
516
516
  }
517
- const invalid$2 = (message) => ({
517
+ const invalid$3 = (message) => ({
518
518
  ok: false,
519
519
  code: "invalid_payload",
520
520
  message
@@ -545,13 +545,13 @@ function attachment(value) {
545
545
  }
546
546
  function finish(input, data) {
547
547
  const id = string(data.id), conversation = string(data.conversation), sender = string(data.sender), destination = string(data.destination);
548
- if (!id || !conversation || !sender || !destination) return invalid$2("Message identity, conversation, sender and destination are required");
549
- if (data.text !== null && data.text !== void 0 && (typeof data.text !== "string" || data.text.length > 1e6)) return invalid$2("Invalid message text");
550
- if (data.media !== void 0 && data.media !== null && (!Array.isArray(data.media) || data.media.length > 50)) return invalid$2("Invalid attachment list");
548
+ if (!id || !conversation || !sender || !destination) return invalid$3("Message identity, conversation, sender and destination are required");
549
+ if (data.text !== null && data.text !== void 0 && (typeof data.text !== "string" || data.text.length > 1e6)) return invalid$3("Invalid message text");
550
+ if (data.media !== void 0 && data.media !== null && (!Array.isArray(data.media) || data.media.length > 50)) return invalid$3("Invalid attachment list");
551
551
  const attachments = (data.media ?? []).map(attachment);
552
- if (attachments.some((a) => !a)) return invalid$2("Attachments require HTTPS references; bytes must be resolved through the authorized file boundary");
552
+ if (attachments.some((a) => !a)) return invalid$3("Attachments require HTTPS references; bytes must be resolved through the authorized file boundary");
553
553
  const time = timestamp(data.time);
554
- if (time === null) return invalid$2("A valid provider timestamp is required");
554
+ if (time === null) return invalid$3("A valid provider timestamp is required");
555
555
  return {
556
556
  ok: true,
557
557
  event: {
@@ -588,17 +588,17 @@ function finish(input, data) {
588
588
  /** Called after the host verifies signatures and resolves the owning connection. */
589
589
  function normalizeMobileConversation(input) {
590
590
  const p = input.payload;
591
- if (!record$2(p)) return invalid$2("Provider payload requires an object");
591
+ if (!record$2(p)) return invalid$3("Provider payload requires an object");
592
592
  if (input.provider === "sendblue") {
593
593
  if (input.type !== "sendblue.message.received") return unsupported$1();
594
- if (p.is_outbound !== false || String(p.status).toUpperCase() !== "RECEIVED" || !phone$1(p.from_number) || !phone$1(p.sendblue_number) || p.to_number !== void 0 && p.to_number !== p.sendblue_number || p.number !== void 0 && p.number !== p.from_number) return invalid$2("Sendblue requires an inbound received message with exact line and contact routing");
594
+ if (p.is_outbound !== false || String(p.status).toUpperCase() !== "RECEIVED" || !phone$1(p.from_number) || !phone$1(p.sendblue_number) || p.to_number !== void 0 && p.to_number !== p.sendblue_number || p.number !== void 0 && p.number !== p.from_number) return invalid$3("Sendblue requires an inbound received message with exact line and contact routing");
595
595
  const service = typeof p.service === "string" ? p.service.toLowerCase() : null;
596
596
  const transport = service === "imessage" ? "imessage" : service === "sms" ? "sms" : service === "rcs" ? "rcs" : null;
597
597
  const messageType = typeof p.message_type === "string" ? p.message_type.toLowerCase() : null;
598
598
  if (!transport || messageType !== "message" && messageType !== "group") return unsupported$1();
599
599
  const group = messageType === "group" || Boolean(p.group_id);
600
- if (group && !string(p.group_id, 256)) return invalid$2("Group messages require a group id");
601
- if (p.media_url !== void 0 && p.media_url !== null && typeof p.media_url !== "string") return invalid$2("Invalid Sendblue media URL");
600
+ if (group && !string(p.group_id, 256)) return invalid$3("Group messages require a group id");
601
+ if (p.media_url !== void 0 && p.media_url !== null && typeof p.media_url !== "string") return invalid$3("Invalid Sendblue media URL");
602
602
  return finish(input, {
603
603
  id: p.message_handle,
604
604
  conversation: group ? p.group_id : JSON.stringify([
@@ -620,21 +620,21 @@ function normalizeMobileConversation(input) {
620
620
  }
621
621
  if (input.provider === "twilio-sms") {
622
622
  if (input.type !== "twilio-sms.message.received") return unsupported$1();
623
- if (!/^AC[a-f\d]{32}$/i.test(String(p.AccountSid ?? "")) || !phone$1(p.From) || !phone$1(p.To) || !/^(SM|MM)[a-f\d]{32}$/i.test(String(p.MessageSid ?? ""))) return invalid$2("Twilio message requires its signed account, SID, and phone routing");
623
+ if (!/^AC[a-f\d]{32}$/i.test(String(p.AccountSid ?? "")) || !phone$1(p.From) || !phone$1(p.To) || !/^(SM|MM)[a-f\d]{32}$/i.test(String(p.MessageSid ?? ""))) return invalid$3("Twilio message requires its signed account, SID, and phone routing");
624
624
  const count = Number(p.NumMedia ?? 0);
625
- if (!Number.isSafeInteger(count) || count < 0 || count > 10) return invalid$2("Invalid Twilio media count");
625
+ if (!Number.isSafeInteger(count) || count < 0 || count > 10) return invalid$3("Invalid Twilio media count");
626
626
  const media = [];
627
627
  for (let index = 0; index < count; index++) {
628
628
  const rawUrl = string(p[`MediaUrl${index}`], 8192);
629
- if (!rawUrl) return invalid$2("Missing Twilio media URL");
629
+ if (!rawUrl) return invalid$3("Missing Twilio media URL");
630
630
  let url;
631
631
  try {
632
632
  url = new URL(rawUrl);
633
633
  } catch {
634
- return invalid$2("Invalid Twilio media URL");
634
+ return invalid$3("Invalid Twilio media URL");
635
635
  }
636
636
  const parts = /^\/2010-04-01\/Accounts\/(AC[a-f\d]{32})\/Messages\/((?:SM|MM)[a-f\d]{32})\/Media\/(ME[a-f\d]{32})$/i.exec(url.pathname);
637
- if (url.origin !== "https://api.twilio.com" || url.username || url.password || url.search || !parts || parts[1].toLowerCase() !== String(p.AccountSid).toLowerCase() || parts[2].toLowerCase() !== String(p.MessageSid).toLowerCase()) return invalid$2("Twilio media URL must belong to the signed message and account");
637
+ if (url.origin !== "https://api.twilio.com" || url.username || url.password || url.search || !parts || parts[1].toLowerCase() !== String(p.AccountSid).toLowerCase() || parts[2].toLowerCase() !== String(p.MessageSid).toLowerCase()) return invalid$3("Twilio media URL must belong to the signed message and account");
638
638
  media.push({
639
639
  id: parts[3],
640
640
  url: rawUrl,
@@ -657,13 +657,13 @@ function normalizeMobileConversation(input) {
657
657
  transport: "sms"
658
658
  });
659
659
  }
660
- if (!record$2(p.data)) return invalid$2("Provider payload requires a data object");
660
+ if (!record$2(p.data)) return invalid$3("Provider payload requires a data object");
661
661
  const data = p.data;
662
662
  if (input.provider === "inkbox") {
663
- if (input.type !== `inkbox.${p.event_type}`) return invalid$2("Event type does not match the provider envelope");
663
+ if (input.type !== `inkbox.${p.event_type}`) return invalid$3("Event type does not match the provider envelope");
664
664
  if (p.event_type === "imessage.received") {
665
665
  const m = data.message;
666
- if (!record$2(m) || m.direction !== "inbound") return invalid$2("Expected an inbound iMessage");
666
+ if (!record$2(m) || m.direction !== "inbound") return invalid$3("Expected an inbound iMessage");
667
667
  return finish(input, {
668
668
  id: m.id,
669
669
  conversation: m.conversation_id,
@@ -678,7 +678,7 @@ function normalizeMobileConversation(input) {
678
678
  }
679
679
  if (p.event_type === "text.received") {
680
680
  const m = data.text_message;
681
- if (!record$2(m) || m.direction !== "inbound") return invalid$2("Expected an inbound phone text");
681
+ if (!record$2(m) || m.direction !== "inbound") return invalid$3("Expected an inbound phone text");
682
682
  return finish(input, {
683
683
  id: m.id,
684
684
  conversation: m.conversation_id,
@@ -694,7 +694,7 @@ function normalizeMobileConversation(input) {
694
694
  }
695
695
  if (p.event_type === "message.received") {
696
696
  const m = data.message;
697
- if (!record$2(m) || m.direction !== "inbound") return invalid$2("Expected inbound mail");
697
+ if (!record$2(m) || m.direction !== "inbound") return invalid$3("Expected inbound mail");
698
698
  return finish(input, {
699
699
  id: m.id,
700
700
  conversation: m.thread_id ?? m.id,
@@ -713,17 +713,17 @@ function normalizeMobileConversation(input) {
713
713
  return unsupported$1();
714
714
  }
715
715
  if (input.provider === "linq") {
716
- if (input.type !== `linq.${p.event_type}`) return invalid$2("Event type does not match the provider envelope");
716
+ if (input.type !== `linq.${p.event_type}`) return invalid$3("Event type does not match the provider envelope");
717
717
  if (p.event_type !== "message.received") return unsupported$1();
718
- if (p.webhook_version !== "2026-02-03" || data.direction !== "inbound" || !record$2(data.chat) || !record$2(data.sender_handle) || !record$2(data.chat.owner_handle) || data.chat.owner_handle.is_me !== true || data.sender_handle.is_me === true) return invalid$2("Linq requires v2026-02-03 incoming payloads with explicit sender and owner handles");
718
+ if (p.webhook_version !== "2026-02-03" || data.direction !== "inbound" || !record$2(data.chat) || !record$2(data.sender_handle) || !record$2(data.chat.owner_handle) || data.chat.owner_handle.is_me !== true || data.sender_handle.is_me === true) return invalid$3("Linq requires v2026-02-03 incoming payloads with explicit sender and owner handles");
719
719
  const transport = data.service === "iMessage" ? "imessage" : data.service === "SMS" ? "sms" : data.service === "RCS" ? "rcs" : null;
720
- if (!transport) return invalid$2("Linq incoming message requires its actual service");
721
- if (!Array.isArray(data.parts) || data.parts.length > 50) return invalid$2("Invalid Linq parts");
720
+ if (!transport) return invalid$3("Linq incoming message requires its actual service");
721
+ if (!Array.isArray(data.parts) || data.parts.length > 50) return invalid$3("Invalid Linq parts");
722
722
  const texts = [], media = [];
723
723
  for (const part of data.parts) {
724
- if (!record$2(part)) return invalid$2("Invalid Linq part");
724
+ if (!record$2(part)) return invalid$3("Invalid Linq part");
725
725
  if (part.type === "text" || part.type === "link") {
726
- if (typeof part.value !== "string") return invalid$2("Invalid Linq text");
726
+ if (typeof part.value !== "string") return invalid$3("Invalid Linq text");
727
727
  texts.push(part.value);
728
728
  } else if (part.type === "media") media.push(part);
729
729
  else return unsupported$1();
@@ -744,13 +744,13 @@ function normalizeMobileConversation(input) {
744
744
  });
745
745
  }
746
746
  if (input.provider === "contiguity") {
747
- if (input.type !== `contiguity.${p.type}`) return invalid$2("Event type does not match the provider envelope");
747
+ if (input.type !== `contiguity.${p.type}`) return invalid$3("Event type does not match the provider envelope");
748
748
  if (![
749
749
  "imessage.incoming",
750
750
  "text.incoming.sms",
751
751
  "text.incoming.mms"
752
752
  ].includes(String(p.type))) return unsupported$1();
753
- if (!string(data.to, 320) || !string(data.from, 320)) return invalid$2("Missing Contiguity phone routing");
753
+ if (!string(data.to, 320) || !string(data.from, 320)) return invalid$3("Missing Contiguity phone routing");
754
754
  return finish(input, {
755
755
  id: p.id,
756
756
  conversation: JSON.stringify([
@@ -782,7 +782,7 @@ function address(value) {
782
782
  if (typeof value !== "string" || value.length > 320) return null;
783
783
  return /^(?:[^<>]*<)?([^<>\s]+@[^<>\s]+)(?:>)?$/.exec(value.trim())?.[1]?.toLowerCase() ?? null;
784
784
  }
785
- const invalid$1 = (message) => ({
785
+ const invalid$2 = (message) => ({
786
786
  ok: false,
787
787
  code: "invalid_payload",
788
788
  message
@@ -790,13 +790,13 @@ const invalid$1 = (message) => ({
790
790
  /** The host adds the provider-read email after verifying the notification. */
791
791
  function normalizeResendConversation(input) {
792
792
  const payload = input.payload;
793
- if (input.type !== "resend.email.received" || !record$1(payload) || payload.type !== "email.received" || !record$1(payload.data) || !record$1(payload.received)) return invalid$1("Resend requires a hydrated received-email notification");
793
+ if (input.type !== "resend.email.received" || !record$1(payload) || payload.type !== "email.received" || !record$1(payload.data) || !record$1(payload.received)) return invalid$2("Resend requires a hydrated received-email notification");
794
794
  const data = payload.data, received = payload.received;
795
- if (typeof data.email_id !== "string" || received.id !== data.email_id || !Array.isArray(received.to) || received.to.length < 1 || received.to.length > 50 || received.cc !== void 0 && (!Array.isArray(received.cc) || received.cc.length > 50) || !address(received.from) || received.text != null && typeof received.text !== "string" || typeof received.created_at !== "string" || !Number.isFinite(Date.parse(received.created_at))) return invalid$1("Resend email identity, sender, recipient, body or time is invalid");
795
+ if (typeof data.email_id !== "string" || received.id !== data.email_id || !Array.isArray(received.to) || received.to.length < 1 || received.to.length > 50 || received.cc !== void 0 && (!Array.isArray(received.cc) || received.cc.length > 50) || !address(received.from) || received.text != null && typeof received.text !== "string" || typeof received.created_at !== "string" || !Number.isFinite(Date.parse(received.created_at))) return invalid$2("Resend email identity, sender, recipient, body or time is invalid");
796
796
  const recipients = [...received.to, ...received.cc ?? []].map(address);
797
- if (recipients.some((item) => !item)) return invalid$1("Resend recipient address is invalid");
797
+ if (recipients.some((item) => !item)) return invalid$2("Resend recipient address is invalid");
798
798
  const attachments = Array.isArray(received.attachments) ? received.attachments : [];
799
- if (attachments.length > 50 || attachments.some((item) => !record$1(item) || typeof item.id !== "string")) return invalid$1("Resend attachments require provider ids");
799
+ if (attachments.length > 50 || attachments.some((item) => !record$1(item) || typeof item.id !== "string")) return invalid$2("Resend attachments require provider ids");
800
800
  const sender = address(received.from);
801
801
  return {
802
802
  ok: true,
@@ -841,6 +841,106 @@ function normalizeResendConversation(input) {
841
841
  };
842
842
  }
843
843
  //#endregion
844
+ //#region src/conversation-events/telegram.ts
845
+ function object$1(value) {
846
+ return value !== null && typeof value === "object" && !Array.isArray(value);
847
+ }
848
+ function integer(value, positive = true) {
849
+ return typeof value === "number" && Number.isSafeInteger(value) && (positive ? value > 0 : value !== 0);
850
+ }
851
+ const invalid$1 = (message) => ({
852
+ ok: false,
853
+ code: "invalid_payload",
854
+ message
855
+ });
856
+ /** Parse only new human messages. The verified webhook proves origin; the host
857
+ * must still check live bot membership and the sender's authority before acting.
858
+ * Addresses include chat, forum topic and sender to prevent session reuse across
859
+ * groups, topics or people. Anonymous/channel senders cannot acquire user rights. */
860
+ function normalizeTelegramConversation(input) {
861
+ if (input.type !== "telegram.message") return {
862
+ ok: false,
863
+ code: "unsupported_event",
864
+ message: "Not a new Telegram message"
865
+ };
866
+ const envelope = input.payload;
867
+ if (!object$1(envelope) || !Number.isSafeInteger(envelope.update_id) || envelope.update_id < 0 || !object$1(envelope.message)) return invalid$1("Telegram requires an update id and message");
868
+ const message = envelope.message;
869
+ const chat = message.chat;
870
+ const from = message.from;
871
+ if (!object$1(chat) || !object$1(from) || !integer(chat.id, false) || !integer(from.id) || from.is_bot !== false || message.sender_chat !== void 0 || !integer(message.message_id) || !integer(message.date) || !Number.isSafeInteger(message.date * 1e3) || ![
872
+ "private",
873
+ "group",
874
+ "supergroup"
875
+ ].includes(String(chat.type)) || (chat.type === "private" ? chat.id !== from.id : chat.id >= 0)) return invalid$1("Telegram requires a human sender and supported chat identity");
876
+ const topic = message.message_thread_id;
877
+ if (topic !== void 0 && (!integer(topic) || chat.type !== "supergroup")) return invalid$1("Invalid Telegram topic");
878
+ const text = message.text ?? message.caption ?? "";
879
+ if (typeof text !== "string" || text.length > 4096 || text.includes("\0")) return invalid$1("Invalid Telegram message text");
880
+ const media = [];
881
+ if (message.photo !== void 0) {
882
+ if (!Array.isArray(message.photo) || message.photo.length === 0 || message.photo.length > 20) return invalid$1("Invalid Telegram photo");
883
+ media.push(message.photo[message.photo.length - 1]);
884
+ }
885
+ for (const kind of [
886
+ "document",
887
+ "audio",
888
+ "voice",
889
+ "video",
890
+ "video_note",
891
+ "animation",
892
+ "sticker"
893
+ ]) if (message[kind] !== void 0) media.push(message[kind]);
894
+ const attachments = [];
895
+ for (const file of media) {
896
+ if (!object$1(file) || typeof file.file_id !== "string" || !/^[A-Za-z0-9_-]{1,512}$/.test(file.file_id) || file.file_size !== void 0 && (!Number.isSafeInteger(file.file_size) || file.file_size < 0)) return invalid$1("Invalid Telegram attachment");
897
+ attachments.push({
898
+ id: file.file_id,
899
+ name: typeof file.file_name === "string" ? file.file_name.slice(0, 255) : null,
900
+ contentType: typeof file.mime_type === "string" ? file.mime_type.slice(0, 200) : null,
901
+ size: typeof file.file_size === "number" ? file.file_size : null,
902
+ contentBase64: null,
903
+ url: null
904
+ });
905
+ }
906
+ if (!text.trim() && attachments.length === 0) return {
907
+ ok: false,
908
+ code: "unsupported_event",
909
+ message: "No message content"
910
+ };
911
+ return {
912
+ ok: true,
913
+ event: {
914
+ version: 1,
915
+ provider: "telegram",
916
+ eventType: input.type,
917
+ operation: "created",
918
+ eventId: `${chat.id}:${message.message_id}`,
919
+ conversationId: String(chat.id),
920
+ parentEventIds: object$1(message.reply_to_message) && integer(message.reply_to_message.message_id) ? [`${chat.id}:${message.reply_to_message.message_id}`] : [],
921
+ sender: {
922
+ id: String(from.id),
923
+ address: `telegram:${chat.id}:${topic ?? 0}:${from.id}`,
924
+ displayName: typeof from.first_name === "string" ? from.first_name.slice(0, 100) : null
925
+ },
926
+ destinations: [{
927
+ kind: "chat",
928
+ id: String(chat.id),
929
+ address: `telegram:${chat.id}`,
930
+ displayName: null
931
+ }],
932
+ subject: null,
933
+ text,
934
+ html: null,
935
+ attachments,
936
+ occurredAt: message.date * 1e3,
937
+ transport: "telegram",
938
+ isGroup: chat.type !== "private",
939
+ historyOnly: false
940
+ }
941
+ };
942
+ }
943
+ //#endregion
844
944
  //#region src/conversation-events/reply.ts
845
945
  function object(value) {
846
946
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
@@ -885,7 +985,27 @@ function buildMessagingReply(input, text, operationId) {
885
985
  const event = normalized.event;
886
986
  if (typeof text !== "string" || !text.trim() || text.length > 1e4 || text.includes("\0")) return fail("Reply text is empty or exceeds its limit");
887
987
  if (!validOperationId(operationId)) return fail("A stable operation id is required");
888
- if (event.historyOnly || event.isGroup) return fail("This event requires review or complete input before a reply");
988
+ if (event.historyOnly || event.isGroup && event.provider !== "telegram") return fail("This event requires review or complete input before a reply");
989
+ if (event.provider === "telegram") {
990
+ if (text.length > 4096) return fail("Telegram text is limited to 4096 characters");
991
+ const message = object(object(input.payload).message);
992
+ return {
993
+ ok: true,
994
+ reply: {
995
+ idempotencyKey: operationId,
996
+ action: "telegram.sendMessage",
997
+ input: {
998
+ chat_id: event.conversationId,
999
+ text,
1000
+ reply_parameters: {
1001
+ message_id: message.message_id,
1002
+ allow_sending_without_reply: true
1003
+ },
1004
+ ...message.message_thread_id === void 0 ? {} : { message_thread_id: message.message_thread_id }
1005
+ }
1006
+ }
1007
+ };
1008
+ }
889
1009
  const data = object(object(input.payload).data);
890
1010
  if (event.provider === "inkbox") {
891
1011
  if (event.eventType === "inkbox.imessage.received") return {
@@ -1068,6 +1188,15 @@ function buildMessagingMediaReply(input, media, operationId) {
1068
1188
  //#endregion
1069
1189
  //#region src/conversation-events/channels.ts
1070
1190
  const channels = [
1191
+ {
1192
+ providerId: "telegram",
1193
+ eventType: "telegram.message",
1194
+ label: "Telegram",
1195
+ transport: "telegram",
1196
+ sourceKind: "connection",
1197
+ replies: true,
1198
+ replyAction: "telegram.sendMessage"
1199
+ },
1071
1200
  {
1072
1201
  providerId: "email",
1073
1202
  eventType: "email.received",
@@ -1465,13 +1594,19 @@ function normalizeConversationEvent(value) {
1465
1594
  "linq-whatsapp",
1466
1595
  "resend",
1467
1596
  "sendblue",
1468
- "twilio-sms"
1597
+ "twilio-sms",
1598
+ "telegram"
1469
1599
  ].includes(String(value.provider))) {
1470
1600
  if (!("type" in value) || typeof value.type !== "string" || !("payload" in value)) return {
1471
1601
  ok: false,
1472
1602
  code: "invalid_payload",
1473
1603
  message: "Provider event requires type and payload"
1474
1604
  };
1605
+ if (value.provider === "telegram") return normalizeTelegramConversation({
1606
+ provider: value.provider,
1607
+ type: value.type,
1608
+ payload: value.payload
1609
+ });
1475
1610
  if (value.provider === "linq-whatsapp") return normalizeLinqWhatsappConversation({
1476
1611
  provider: value.provider,
1477
1612
  type: value.type,