@rudderhq/server 0.3.6-canary.2 → 0.3.6-canary.21

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.
Files changed (230) hide show
  1. package/dist/bootstrap/plugin-host-runtime.d.ts +12 -12
  2. package/dist/bundled-plugins/plugin-linear/dist/worker.js +48 -1
  3. package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +3 -3
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +18 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/routes/access.helpers.d.ts +1 -1
  8. package/dist/routes/activity.d.ts +1 -1
  9. package/dist/routes/activity.d.ts.map +1 -1
  10. package/dist/routes/activity.js +18 -5
  11. package/dist/routes/activity.js.map +1 -1
  12. package/dist/routes/agents.d.ts.map +1 -1
  13. package/dist/routes/agents.js +89 -2
  14. package/dist/routes/agents.js.map +1 -1
  15. package/dist/routes/agents.management-routes.d.ts.map +1 -1
  16. package/dist/routes/agents.management-routes.js +100 -22
  17. package/dist/routes/agents.management-routes.js.map +1 -1
  18. package/dist/routes/chats.d.ts.map +1 -1
  19. package/dist/routes/chats.js +171 -7
  20. package/dist/routes/chats.js.map +1 -1
  21. package/dist/routes/chats.stream-routes.d.ts.map +1 -1
  22. package/dist/routes/chats.stream-routes.js +84 -3
  23. package/dist/routes/chats.stream-routes.js.map +1 -1
  24. package/dist/routes/integrations.d.ts.map +1 -1
  25. package/dist/routes/integrations.js +21 -0
  26. package/dist/routes/integrations.js.map +1 -1
  27. package/dist/routes/issues.comments-attachments.d.ts.map +1 -1
  28. package/dist/routes/issues.comments-attachments.js +6 -3
  29. package/dist/routes/issues.comments-attachments.js.map +1 -1
  30. package/dist/routes/issues.d.ts.map +1 -1
  31. package/dist/routes/issues.js +4 -1
  32. package/dist/routes/issues.js.map +1 -1
  33. package/dist/routes/messenger.d.ts.map +1 -1
  34. package/dist/routes/messenger.js +7 -1
  35. package/dist/routes/messenger.js.map +1 -1
  36. package/dist/services/access.d.ts +7 -7
  37. package/dist/services/activity.d.ts +5 -5
  38. package/dist/services/activity.d.ts.map +1 -1
  39. package/dist/services/activity.js +1 -1
  40. package/dist/services/activity.js.map +1 -1
  41. package/dist/services/agent-run-context.d.ts +12 -0
  42. package/dist/services/agent-run-context.d.ts.map +1 -1
  43. package/dist/services/agent-run-context.js +91 -39
  44. package/dist/services/agent-run-context.js.map +1 -1
  45. package/dist/services/agent-startup-context.d.ts +84 -0
  46. package/dist/services/agent-startup-context.d.ts.map +1 -0
  47. package/dist/services/agent-startup-context.js +347 -0
  48. package/dist/services/agent-startup-context.js.map +1 -0
  49. package/dist/services/agents.d.ts +33 -20
  50. package/dist/services/agents.d.ts.map +1 -1
  51. package/dist/services/agents.js +16 -1
  52. package/dist/services/agents.js.map +1 -1
  53. package/dist/services/approvals.d.ts +5 -5
  54. package/dist/services/assets.d.ts +6 -6
  55. package/dist/services/automation-chat-output.d.ts +3 -3
  56. package/dist/services/automations.d.ts +13 -13
  57. package/dist/services/automations.d.ts.map +1 -1
  58. package/dist/services/automations.js +17 -28
  59. package/dist/services/automations.js.map +1 -1
  60. package/dist/services/board-auth.d.ts +2 -2
  61. package/dist/services/calendar.d.ts +6 -6
  62. package/dist/services/chat-agent-runs.d.ts +1 -0
  63. package/dist/services/chat-agent-runs.d.ts.map +1 -1
  64. package/dist/services/chat-agent-runs.js +5 -0
  65. package/dist/services/chat-agent-runs.js.map +1 -1
  66. package/dist/services/chat-assistant.d.ts.map +1 -1
  67. package/dist/services/chat-assistant.helpers.d.ts +1 -0
  68. package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
  69. package/dist/services/chat-assistant.helpers.js +6 -9
  70. package/dist/services/chat-assistant.helpers.js.map +1 -1
  71. package/dist/services/chat-assistant.js +3 -0
  72. package/dist/services/chat-assistant.js.map +1 -1
  73. package/dist/services/chat-generation-locks.d.ts +6 -1
  74. package/dist/services/chat-generation-locks.d.ts.map +1 -1
  75. package/dist/services/chat-generation-locks.js +20 -2
  76. package/dist/services/chat-generation-locks.js.map +1 -1
  77. package/dist/services/chats.d.ts +391 -74
  78. package/dist/services/chats.d.ts.map +1 -1
  79. package/dist/services/chats.helpers.d.ts +2 -2
  80. package/dist/services/chats.js +341 -3
  81. package/dist/services/chats.js.map +1 -1
  82. package/dist/services/costs.d.ts +3 -3
  83. package/dist/services/finance.d.ts +6 -6
  84. package/dist/services/goals.d.ts +6 -6
  85. package/dist/services/heartbeat.d.ts +1 -1
  86. package/dist/services/heartbeat.d.ts.map +1 -1
  87. package/dist/services/heartbeat.js +1 -1
  88. package/dist/services/heartbeat.js.map +1 -1
  89. package/dist/services/integrations/agent-integrations.d.ts +26 -603
  90. package/dist/services/integrations/agent-integrations.d.ts.map +1 -1
  91. package/dist/services/integrations/agent-integrations.js +32 -2
  92. package/dist/services/integrations/agent-integrations.js.map +1 -1
  93. package/dist/services/integrations/feishu/callback-credentials.d.ts +9 -0
  94. package/dist/services/integrations/feishu/callback-credentials.d.ts.map +1 -0
  95. package/dist/services/integrations/feishu/callback-credentials.js +54 -0
  96. package/dist/services/integrations/feishu/callback-credentials.js.map +1 -0
  97. package/dist/services/integrations/feishu/event-verifier.d.ts +24 -0
  98. package/dist/services/integrations/feishu/event-verifier.d.ts.map +1 -0
  99. package/dist/services/integrations/feishu/event-verifier.js +70 -0
  100. package/dist/services/integrations/feishu/event-verifier.js.map +1 -0
  101. package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts +2 -0
  102. package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts.map +1 -1
  103. package/dist/services/integrations/feishu/inbound-dispatcher-db.js +14 -7
  104. package/dist/services/integrations/feishu/inbound-dispatcher-db.js.map +1 -1
  105. package/dist/services/integrations/feishu/inbound-dispatcher.d.ts +14 -1
  106. package/dist/services/integrations/feishu/inbound-dispatcher.d.ts.map +1 -1
  107. package/dist/services/integrations/feishu/inbound-dispatcher.js +33 -2
  108. package/dist/services/integrations/feishu/inbound-dispatcher.js.map +1 -1
  109. package/dist/services/integrations/feishu/runtime.d.ts +75 -0
  110. package/dist/services/integrations/feishu/runtime.d.ts.map +1 -0
  111. package/dist/services/integrations/feishu/runtime.js +362 -0
  112. package/dist/services/integrations/feishu/runtime.js.map +1 -0
  113. package/dist/services/issue-approvals.d.ts +2 -2
  114. package/dist/services/issues.comments-attachments.d.ts +18 -7
  115. package/dist/services/issues.comments-attachments.d.ts.map +1 -1
  116. package/dist/services/issues.comments-attachments.js +98 -13
  117. package/dist/services/issues.comments-attachments.js.map +1 -1
  118. package/dist/services/issues.d.ts +23 -12
  119. package/dist/services/issues.d.ts.map +1 -1
  120. package/dist/services/issues.helpers.d.ts +2 -0
  121. package/dist/services/issues.helpers.d.ts.map +1 -1
  122. package/dist/services/issues.helpers.js +23 -0
  123. package/dist/services/issues.helpers.js.map +1 -1
  124. package/dist/services/issues.js +3 -3
  125. package/dist/services/issues.js.map +1 -1
  126. package/dist/services/messenger.d.ts +10 -4
  127. package/dist/services/messenger.d.ts.map +1 -1
  128. package/dist/services/messenger.js +163 -24
  129. package/dist/services/messenger.js.map +1 -1
  130. package/dist/services/orgs.d.ts +1 -1
  131. package/dist/services/plugin-registry.d.ts +34 -34
  132. package/dist/services/projects.d.ts +1 -1
  133. package/dist/services/runtime-kernel/heartbeat.core.d.ts +20 -1
  134. package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -1
  135. package/dist/services/runtime-kernel/heartbeat.core.js +152 -12
  136. package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -1
  137. package/dist/services/runtime-kernel/heartbeat.d.ts +10 -10
  138. package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -1
  139. package/dist/services/runtime-kernel/heartbeat.execute.js +64 -16
  140. package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -1
  141. package/dist/services/runtime-kernel/heartbeat.sessions.d.ts.map +1 -1
  142. package/dist/services/runtime-kernel/heartbeat.sessions.js +81 -12
  143. package/dist/services/runtime-kernel/heartbeat.sessions.js.map +1 -1
  144. package/dist/services/secrets.d.ts +15 -15
  145. package/dist/services/workspace-runtime.services.d.ts +3 -3
  146. package/package.json +13 -13
  147. package/resources/bundled-skills/para-memory-files/SKILL.md +34 -8
  148. package/resources/bundled-skills/para-memory-files/evals/conversation-capture.md +26 -0
  149. package/resources/bundled-skills/para-memory-files/references/schemas.md +26 -0
  150. package/resources/bundled-skills/rudder/SKILL.md +9 -0
  151. package/resources/bundled-skills/rudder/references/cli-reference.md +6 -4
  152. package/skills/para-memory-files/SKILL.md +34 -8
  153. package/skills/para-memory-files/evals/conversation-capture.md +26 -0
  154. package/skills/para-memory-files/references/schemas.md +26 -0
  155. package/skills/rudder/SKILL.md +9 -0
  156. package/skills/rudder/references/cli-reference.md +6 -4
  157. package/ui-dist/assets/{_basePickBy-CcD8DFEo.js → _basePickBy-ISxvtQmh.js} +1 -1
  158. package/ui-dist/assets/{_baseUniq-Dol1zTsM.js → _baseUniq-DHI7TVxX.js} +1 -1
  159. package/ui-dist/assets/{arc-CIQpjNW4.js → arc-BUMdDwhB.js} +1 -1
  160. package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-BAgSxOsl.js → architectureDiagram-2XIMDMQ5-C5L1JNhe.js} +1 -1
  161. package/ui-dist/assets/{blockDiagram-WCTKOSBZ-CGyFTorY.js → blockDiagram-WCTKOSBZ-BVufAfZ6.js} +1 -1
  162. package/ui-dist/assets/{c4Diagram-IC4MRINW-CEEqddDU.js → c4Diagram-IC4MRINW-BhHlEAZv.js} +1 -1
  163. package/ui-dist/assets/channel-CVNEMZd5.js +1 -0
  164. package/ui-dist/assets/{chunk-4BX2VUAB-BDGaHIF5.js → chunk-4BX2VUAB-v5kH5_-V.js} +1 -1
  165. package/ui-dist/assets/{chunk-55IACEB6-CSoZuI_8.js → chunk-55IACEB6-TNezZWhV.js} +1 -1
  166. package/ui-dist/assets/{chunk-FMBD7UC4-DrlPlIm5.js → chunk-FMBD7UC4-DJduihz6.js} +1 -1
  167. package/ui-dist/assets/{chunk-JSJVCQXG-DahVPShT.js → chunk-JSJVCQXG-B2jFwzBe.js} +1 -1
  168. package/ui-dist/assets/{chunk-KX2RTZJC-Dh5zWzM8.js → chunk-KX2RTZJC-CdDz3cqH.js} +1 -1
  169. package/ui-dist/assets/{chunk-NQ4KR5QH-BsxpsJJs.js → chunk-NQ4KR5QH-vhQQUT-L.js} +1 -1
  170. package/ui-dist/assets/{chunk-QZHKN3VN-uSnPNcZ5.js → chunk-QZHKN3VN-C4petxFG.js} +1 -1
  171. package/ui-dist/assets/{chunk-WL4C6EOR-Cb_ahVLl.js → chunk-WL4C6EOR-CxpSuOrC.js} +1 -1
  172. package/ui-dist/assets/classDiagram-VBA2DB6C-dXctjUNC.js +1 -0
  173. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-dXctjUNC.js +1 -0
  174. package/ui-dist/assets/clone-DrfVa0Lm.js +1 -0
  175. package/ui-dist/assets/{cose-bilkent-S5V4N54A-DlJDGTnB.js → cose-bilkent-S5V4N54A-Cu-LUWwt.js} +1 -1
  176. package/ui-dist/assets/{dagre-KLK3FWXG-DvnLQute.js → dagre-KLK3FWXG-BznM_tXi.js} +1 -1
  177. package/ui-dist/assets/{diagram-E7M64L7V-CRdm9gWn.js → diagram-E7M64L7V-B9vbnF0G.js} +1 -1
  178. package/ui-dist/assets/{diagram-IFDJBPK2-DZOej-GY.js → diagram-IFDJBPK2-B0K7p5ip.js} +1 -1
  179. package/ui-dist/assets/{diagram-P4PSJMXO-L57zGtmq.js → diagram-P4PSJMXO-B317ppu9.js} +1 -1
  180. package/ui-dist/assets/{erDiagram-INFDFZHY-CSRy8XrP.js → erDiagram-INFDFZHY-DxQn1H79.js} +1 -1
  181. package/ui-dist/assets/{flowDiagram-PKNHOUZH-DDW1GdoS.js → flowDiagram-PKNHOUZH-BRlHfAhO.js} +1 -1
  182. package/ui-dist/assets/{ganttDiagram-A5KZAMGK-rdmcT7DC.js → ganttDiagram-A5KZAMGK-ZPQATwOp.js} +1 -1
  183. package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-Dg6khMQq.js → gitGraphDiagram-K3NZZRJ6-2FSSHn2W.js} +1 -1
  184. package/ui-dist/assets/{graph-rJl07fmI.js → graph-CsZPLb0i.js} +1 -1
  185. package/ui-dist/assets/{index-6XT0f8SC.js → index-0pvUeq7z.js} +1 -1
  186. package/ui-dist/assets/{index-CiIjHYkZ.js → index-3-X7SqUg.js} +1 -1
  187. package/ui-dist/assets/{index-DQABP5G0.js → index-3ucNWY-Q.js} +1 -1
  188. package/ui-dist/assets/{index-Bl7ecGnt.js → index-8RSGq1Wg.js} +1 -1
  189. package/ui-dist/assets/{index-3z9gN6vz.js → index-B8mi4SQV.js} +1 -1
  190. package/ui-dist/assets/{index-BGauRcOh.js → index-BIqU1aGN.js} +1 -1
  191. package/ui-dist/assets/{index-DkiaQfyg.js → index-BWo8nSUI.js} +1 -1
  192. package/ui-dist/assets/index-Bgik3-sp.css +1 -0
  193. package/ui-dist/assets/{index-C65ndIIg.js → index-C1WpEOab.js} +1 -1
  194. package/ui-dist/assets/{index-CjBuwQCg.js → index-C9juwYGf.js} +1 -1
  195. package/ui-dist/assets/{index-BaDAStQB.js → index-CUK1YqbJ.js} +1 -1
  196. package/ui-dist/assets/{index-D_KtoLTQ.js → index-Cgj3Uagb.js} +1 -1
  197. package/ui-dist/assets/{index-CxS_-UO4.js → index-DJAdEjzj.js} +1 -1
  198. package/ui-dist/assets/{index-BfZsNU5h.js → index-DfWM3Q6p.js} +1 -1
  199. package/ui-dist/assets/{index-BEWhrdwh.js → index-DowAq2x5.js} +1 -1
  200. package/ui-dist/assets/{index-DGHRHBKO.js → index-DuTOtG2a.js} +1 -1
  201. package/ui-dist/assets/{index-CqfiMpHY.js → index-KNsGlYUl.js} +1 -1
  202. package/ui-dist/assets/{index-jadvIFpg.js → index-NFMzhEMm.js} +1 -1
  203. package/ui-dist/assets/{index-BlJROSd_.js → index-uK_jgMIY.js} +447 -442
  204. package/ui-dist/assets/{infoDiagram-LFFYTUFH-DEymHZr8.js → infoDiagram-LFFYTUFH-BgBXtPzj.js} +1 -1
  205. package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-B1F9V87B.js → ishikawaDiagram-PHBUUO56-Br_xLiU5.js} +1 -1
  206. package/ui-dist/assets/{journeyDiagram-4ABVD52K-wXBUBo_k.js → journeyDiagram-4ABVD52K-BAuuTIbm.js} +1 -1
  207. package/ui-dist/assets/{kanban-definition-K7BYSVSG-Douzrzlt.js → kanban-definition-K7BYSVSG-8NU1bqkN.js} +1 -1
  208. package/ui-dist/assets/{layout-bPOlN3pV.js → layout-DVTXzgPf.js} +1 -1
  209. package/ui-dist/assets/{linear-6GPY4A_9.js → linear-BYaSYTI4.js} +1 -1
  210. package/ui-dist/assets/{mermaid.core-zeNDPCvd.js → mermaid.core-D4Wu9eUI.js} +4 -4
  211. package/ui-dist/assets/{mindmap-definition-YRQLILUH-BzOSHeev.js → mindmap-definition-YRQLILUH-c_2HEgE4.js} +1 -1
  212. package/ui-dist/assets/{pieDiagram-SKSYHLDU-BzeTtbMZ.js → pieDiagram-SKSYHLDU-CGRMShDr.js} +1 -1
  213. package/ui-dist/assets/{quadrantDiagram-337W2JSQ-BXuYu1eP.js → quadrantDiagram-337W2JSQ-CooS1cJi.js} +1 -1
  214. package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-BXOk_5q0.js → requirementDiagram-Z7DCOOCP-PfB17V04.js} +1 -1
  215. package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK-c5Oi3One.js → sankeyDiagram-WA2Y5GQK-S5EYlVvD.js} +1 -1
  216. package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-83aGU0n9.js → sequenceDiagram-2WXFIKYE-Bl2xrmxE.js} +1 -1
  217. package/ui-dist/assets/{stateDiagram-RAJIS63D-DHQtOybw.js → stateDiagram-RAJIS63D-mqqvpOjv.js} +1 -1
  218. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-BvzZKEX9.js +1 -0
  219. package/ui-dist/assets/{timeline-definition-YZTLITO2-GpY269qE.js → timeline-definition-YZTLITO2-n9U6Vtk4.js} +1 -1
  220. package/ui-dist/assets/{treemap-KZPCXAKY-HNAJqXUS.js → treemap-KZPCXAKY-Dw__9-kb.js} +1 -1
  221. package/ui-dist/assets/{vennDiagram-LZ73GAT5-xnvz7co6.js → vennDiagram-LZ73GAT5-CetcOiXZ.js} +1 -1
  222. package/ui-dist/assets/{xychartDiagram-JWTSCODW-DLsulaPB.js → xychartDiagram-JWTSCODW-Drfx0k7A.js} +1 -1
  223. package/ui-dist/brands/cursor-app-icon.svg +4 -0
  224. package/ui-dist/index.html +2 -2
  225. package/ui-dist/assets/channel-BrjzfGTO.js +0 -1
  226. package/ui-dist/assets/classDiagram-VBA2DB6C-BHMaQipn.js +0 -1
  227. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-BHMaQipn.js +0 -1
  228. package/ui-dist/assets/clone-PUUtvoP8.js +0 -1
  229. package/ui-dist/assets/index-Dv6aTCoB.css +0 -1
  230. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-BdRV3T4l.js +0 -1
@@ -9,6 +9,7 @@ import { issueLowSignalContentOnlyActivitySql } from "./issue-activity-filters.j
9
9
  const ISSUE_ACTIVITY_ACTIONS = [
10
10
  "issue.updated",
11
11
  "issue.followed",
12
+ "automation.issue_created_notification",
12
13
  "issue.approval_linked",
13
14
  "issue.work_product_created",
14
15
  "issue.work_product_updated",
@@ -268,6 +269,8 @@ function summarizeIssueActivity(activity, issue) {
268
269
  }
269
270
  case "issue.followed":
270
271
  return "Followed";
272
+ case "automation.issue_created_notification":
273
+ return "Automation created issue";
271
274
  case "issue.approval_linked":
272
275
  return "Approval linked";
273
276
  case "issue.work_product_created":
@@ -563,7 +566,7 @@ function failedRunCard(run, agentName) {
563
566
  href: `/agents/${run.agentId}/runs/${run.id}`,
564
567
  latestActivityAt: run.updatedAt ?? run.createdAt,
565
568
  actions: [
566
- buildAction("Retry", `/heartbeat-runs/${run.id}/retry`, "POST"),
569
+ buildAction("Retry", `/agent-runs/${run.id}/retry`, "POST"),
567
570
  buildAction("Open run", `/agents/${run.agentId}/runs/${run.id}`, "GET"),
568
571
  ],
569
572
  metadata: {
@@ -652,6 +655,16 @@ export function messengerService(db) {
652
655
  function chatConversationIdFromThreadKey(threadKey) {
653
656
  return threadKey.startsWith("chat:") ? threadKey.slice("chat:".length) : null;
654
657
  }
658
+ function issueIdFromThreadKey(threadKey) {
659
+ return threadKey.startsWith("issue:") ? threadKey.slice("issue:".length) : null;
660
+ }
661
+ function isSyntheticMessengerThreadKey(threadKey) {
662
+ return threadKey === "issues"
663
+ || threadKey === "approvals"
664
+ || threadKey === "failed-runs"
665
+ || threadKey === "budget-alerts"
666
+ || threadKey === "join-requests";
667
+ }
655
668
  async function getCustomGroupOrThrow(orgId, userId, groupId) {
656
669
  const [group] = await db
657
670
  .select()
@@ -662,14 +675,72 @@ export function messengerService(db) {
662
675
  throw notFound("Messenger custom group not found");
663
676
  return group;
664
677
  }
665
- async function ensureChatThreadCanBeGrouped(orgId, userId, threadKey) {
678
+ async function loadIssueThreadSummaryById(orgId, userId, issueId) {
679
+ const lastReadAtPromise = lastReadAtForThread(db, orgId, userId, "issues");
680
+ const rows = (await db.execute(issueEntryRowsQuery(orgId, userId, sql `
681
+ where id = ${issueId}
682
+ limit 1
683
+ `)));
684
+ const entry = rows[0] ? issueThreadEntryFromRow(rows[0], userId) : null;
685
+ if (!entry)
686
+ return null;
687
+ const [card] = await buildIssueCardsForEntries(orgId, userId, [entry], "latest");
688
+ if (!card)
689
+ return null;
690
+ const lastReadAt = await lastReadAtPromise;
691
+ const issueThreadStates = await loadThreadStates(db, orgId, userId, [`issue:${issueId}`]);
692
+ return splitIssueSummary(card.entry, card.item, lastReadAt, issueThreadStates.get(`issue:${issueId}`) ?? null);
693
+ }
694
+ async function loadSyntheticThreadSummaryByKey(orgId, userId, threadKey) {
695
+ const syntheticThreadStates = loadThreadStates(db, orgId, userId, [
696
+ "issues",
697
+ "approvals",
698
+ "failed-runs",
699
+ "budget-alerts",
700
+ "join-requests",
701
+ ]);
702
+ switch (threadKey) {
703
+ case "issues": {
704
+ const data = await loadIssueThreadSummaryData(orgId, userId, syntheticThreadStates);
705
+ return data.itemCount > 0 ? data.summary : null;
706
+ }
707
+ case "approvals": {
708
+ const data = await loadApprovalThreadSummaryData(orgId, userId, syntheticThreadStates);
709
+ return data.itemCount > 0 ? data.summary : null;
710
+ }
711
+ case "failed-runs": {
712
+ const data = await loadFailedRunSummaryData(orgId, userId, syntheticThreadStates);
713
+ return data.itemCount > 0 ? data.summary : null;
714
+ }
715
+ case "budget-alerts": {
716
+ const data = await loadBudgetAlertData(orgId, userId, syntheticThreadStates);
717
+ return data.detail.items.length > 0 ? data.summary : null;
718
+ }
719
+ case "join-requests": {
720
+ const data = await loadJoinRequestSummaryData(orgId, userId, syntheticThreadStates);
721
+ return data.itemCount > 0 ? data.summary : null;
722
+ }
723
+ default:
724
+ return null;
725
+ }
726
+ }
727
+ async function findMessengerThreadSummary(orgId, userId, threadKey) {
666
728
  const conversationId = chatConversationIdFromThreadKey(threadKey);
667
- if (!conversationId) {
668
- throw badRequest("Only chat threads can be added to custom Messenger groups");
729
+ if (conversationId) {
730
+ const conversations = await chatsSvc.listSummariesByIds(orgId, [conversationId], userId);
731
+ const conversation = conversations[0];
732
+ return conversation ? chatSummary(conversation) : null;
669
733
  }
670
- const conversations = await chatsSvc.listSummariesByIds(orgId, [conversationId], userId);
671
- if (conversations.length === 0) {
672
- throw notFound("Messenger chat thread not found");
734
+ const issueId = issueIdFromThreadKey(threadKey);
735
+ if (issueId) {
736
+ return loadIssueThreadSummaryById(orgId, userId, issueId);
737
+ }
738
+ return loadSyntheticThreadSummaryByKey(orgId, userId, threadKey);
739
+ }
740
+ async function ensureMessengerThreadCanBeGrouped(orgId, userId, threadKey) {
741
+ const summary = await findMessengerThreadSummary(orgId, userId, threadKey);
742
+ if (!summary) {
743
+ throw notFound("Messenger thread not found");
673
744
  }
674
745
  }
675
746
  async function listCustomGroups(orgId, userId) {
@@ -678,17 +749,15 @@ export function messengerService(db) {
678
749
  .select()
679
750
  .from(messengerCustomGroups)
680
751
  .where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId)))
681
- .orderBy(asc(messengerCustomGroups.sortOrder), asc(messengerCustomGroups.createdAt)),
752
+ .orderBy(sql `${messengerCustomGroups.pinnedAt} IS NULL`, asc(messengerCustomGroups.sortOrder), asc(messengerCustomGroups.createdAt)),
682
753
  db
683
754
  .select()
684
755
  .from(messengerCustomGroupEntries)
685
756
  .where(and(eq(messengerCustomGroupEntries.orgId, orgId), eq(messengerCustomGroupEntries.userId, userId)))
686
757
  .orderBy(asc(messengerCustomGroupEntries.sortOrder), asc(messengerCustomGroupEntries.createdAt)),
687
758
  ]);
688
- const chatThreadKeys = entries
759
+ const conversationIds = entries
689
760
  .map((entry) => entry.threadKey)
690
- .filter((threadKey) => Boolean(chatConversationIdFromThreadKey(threadKey)));
691
- const conversationIds = chatThreadKeys
692
761
  .map((threadKey) => chatConversationIdFromThreadKey(threadKey))
693
762
  .filter((id) => Boolean(id));
694
763
  const conversations = await chatsSvc.listSummariesByIds(orgId, conversationIds, userId);
@@ -696,11 +765,36 @@ export function messengerService(db) {
696
765
  const summary = chatSummary(conversation);
697
766
  return [summary.threadKey, summary];
698
767
  }));
768
+ const nonChatThreadKeys = [...new Set(entries
769
+ .map((entry) => entry.threadKey)
770
+ .filter((threadKey) => !chatConversationIdFromThreadKey(threadKey)))];
771
+ const issueThreadKeys = nonChatThreadKeys.filter((threadKey) => Boolean(issueIdFromThreadKey(threadKey)));
772
+ if (nonChatThreadKeys.length > 0) {
773
+ const syntheticThreadKeys = nonChatThreadKeys.filter((threadKey) => !issueIdFromThreadKey(threadKey));
774
+ const [issueSummaries, syntheticSummaries] = await Promise.all([
775
+ Promise.all(issueThreadKeys.map(async (threadKey) => {
776
+ const issueId = issueIdFromThreadKey(threadKey);
777
+ return issueId ? loadIssueThreadSummaryById(orgId, userId, issueId) : null;
778
+ })),
779
+ Promise.all(syntheticThreadKeys.map((threadKey) => loadSyntheticThreadSummaryByKey(orgId, userId, threadKey))),
780
+ ]);
781
+ for (const summary of issueSummaries) {
782
+ if (summary)
783
+ summaryByThreadKey.set(summary.threadKey, summary);
784
+ }
785
+ for (const summary of syntheticSummaries) {
786
+ if (summary)
787
+ summaryByThreadKey.set(summary.threadKey, summary);
788
+ }
789
+ }
699
790
  const staleEntryIds = [];
700
791
  const entriesByGroupId = new Map();
701
792
  for (const entry of entries) {
702
793
  const summary = summaryByThreadKey.get(entry.threadKey);
703
794
  if (!summary) {
795
+ if (isSyntheticMessengerThreadKey(entry.threadKey)) {
796
+ continue;
797
+ }
704
798
  staleEntryIds.push(entry.id);
705
799
  continue;
706
800
  }
@@ -726,15 +820,15 @@ export function messengerService(db) {
726
820
  })),
727
821
  };
728
822
  }
729
- async function createCustomGroup(orgId, userId, name, icon = null) {
730
- const [lastGroup] = await db
823
+ async function createCustomGroupWithClient(client, orgId, userId, name, icon = null) {
824
+ const [lastGroup] = await client
731
825
  .select({ sortOrder: messengerCustomGroups.sortOrder })
732
826
  .from(messengerCustomGroups)
733
827
  .where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId)))
734
828
  .orderBy(desc(messengerCustomGroups.sortOrder))
735
829
  .limit(1);
736
830
  const now = new Date();
737
- const [group] = await db
831
+ const [group] = await client
738
832
  .insert(messengerCustomGroups)
739
833
  .values({
740
834
  orgId,
@@ -742,17 +836,26 @@ export function messengerService(db) {
742
836
  name,
743
837
  icon,
744
838
  sortOrder: (lastGroup?.sortOrder ?? -1) + 1,
839
+ pinnedAt: now,
745
840
  updatedAt: now,
746
841
  })
747
842
  .returning();
748
843
  return group;
749
844
  }
845
+ async function createCustomGroup(orgId, userId, name, icon = null) {
846
+ return createCustomGroupWithClient(db, orgId, userId, name, icon);
847
+ }
750
848
  async function updateCustomGroup(orgId, userId, groupId, patch) {
751
849
  await getCustomGroupOrThrow(orgId, userId, groupId);
850
+ const { pinned, ...groupPatch } = patch;
851
+ const updatePatch = {
852
+ ...groupPatch,
853
+ ...(typeof pinned === "boolean" ? { pinnedAt: pinned ? new Date() : null } : {}),
854
+ };
752
855
  const [group] = await db
753
856
  .update(messengerCustomGroups)
754
857
  .set({
755
- ...patch,
858
+ ...updatePatch,
756
859
  updatedAt: new Date(),
757
860
  })
758
861
  .where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId), eq(messengerCustomGroups.id, groupId)))
@@ -790,17 +893,16 @@ export function messengerService(db) {
790
893
  });
791
894
  return listCustomGroups(orgId, userId);
792
895
  }
793
- async function assignThreadToCustomGroup(orgId, userId, groupId, threadKey) {
794
- await getCustomGroupOrThrow(orgId, userId, groupId);
795
- await ensureChatThreadCanBeGrouped(orgId, userId, threadKey);
796
- const [lastEntry] = await db
896
+ async function assignThreadToCustomGroupWithClient(client, orgId, userId, groupId, threadKey) {
897
+ await ensureMessengerThreadCanBeGrouped(orgId, userId, threadKey);
898
+ const [lastEntry] = await client
797
899
  .select({ sortOrder: messengerCustomGroupEntries.sortOrder })
798
900
  .from(messengerCustomGroupEntries)
799
901
  .where(and(eq(messengerCustomGroupEntries.orgId, orgId), eq(messengerCustomGroupEntries.userId, userId), eq(messengerCustomGroupEntries.groupId, groupId)))
800
902
  .orderBy(desc(messengerCustomGroupEntries.sortOrder))
801
903
  .limit(1);
802
904
  const now = new Date();
803
- const [entry] = await db
905
+ const [entry] = await client
804
906
  .insert(messengerCustomGroupEntries)
805
907
  .values({
806
908
  orgId,
@@ -825,6 +927,22 @@ export function messengerService(db) {
825
927
  .returning();
826
928
  return entry;
827
929
  }
930
+ async function assignThreadToCustomGroup(orgId, userId, groupId, threadKey) {
931
+ await getCustomGroupOrThrow(orgId, userId, groupId);
932
+ return assignThreadToCustomGroupWithClient(db, orgId, userId, groupId, threadKey);
933
+ }
934
+ async function createCustomGroupWithEntries(orgId, userId, name, icon, threadKeys) {
935
+ const uniqueThreadKeys = [...new Set(threadKeys)];
936
+ if (uniqueThreadKeys.length === 0)
937
+ throw badRequest("At least one thread key is required");
938
+ await db.transaction(async (tx) => {
939
+ const group = await createCustomGroupWithClient(tx, orgId, userId, name, icon);
940
+ for (const threadKey of uniqueThreadKeys) {
941
+ await assignThreadToCustomGroupWithClient(tx, orgId, userId, group.id, threadKey);
942
+ }
943
+ });
944
+ return listCustomGroups(orgId, userId);
945
+ }
828
946
  async function removeThreadFromCustomGroups(orgId, userId, threadKey) {
829
947
  await db
830
948
  .delete(messengerCustomGroupEntries)
@@ -885,6 +1003,17 @@ export function messengerService(db) {
885
1003
  where ${issueFollows.orgId} = ${orgId}
886
1004
  and ${issueFollows.userId} = ${userId}
887
1005
  and followed_issue.hidden_at is null
1006
+ union
1007
+ select notification_issue.id as id
1008
+ from ${activityLog} automation_notification_activity
1009
+ inner join ${issues} notification_issue
1010
+ on automation_notification_activity.entity_id = notification_issue.id::text
1011
+ and notification_issue.org_id = automation_notification_activity.org_id
1012
+ where automation_notification_activity.org_id = ${orgId}
1013
+ and automation_notification_activity.entity_type = 'issue'
1014
+ and automation_notification_activity.action = 'automation.issue_created_notification'
1015
+ and automation_notification_activity.details->>'userId' = ${userId}
1016
+ and notification_issue.hidden_at is null
888
1017
  ),
889
1018
  issue_entries as (
890
1019
  select
@@ -979,6 +1108,15 @@ export function messengerService(db) {
979
1108
  and automation_follow_row.user_id = ${userId}
980
1109
  and automation_follow_row.issue_id = issue_row.id
981
1110
  )
1111
+ or exists (
1112
+ select 1
1113
+ from ${activityLog} automation_notification_visibility
1114
+ where automation_notification_visibility.org_id = ${orgId}
1115
+ and automation_notification_visibility.entity_type = 'issue'
1116
+ and automation_notification_visibility.entity_id = issue_row.id::text
1117
+ and automation_notification_visibility.action = 'automation.issue_created_notification'
1118
+ and automation_notification_visibility.details->>'userId' = ${userId}
1119
+ )
982
1120
  )
983
1121
  left join lateral (
984
1122
  select
@@ -1382,7 +1520,6 @@ export function messengerService(db) {
1382
1520
  }
1383
1521
  async function loadApprovalThreadSummaryData(orgId, userId, threadStates) {
1384
1522
  const lastReadAt = await lastReadAtForThread(db, orgId, userId, "approvals", threadStates);
1385
- const approvalPredicate = eq(approvals.orgId, orgId);
1386
1523
  const pendingApprovalPredicate = and(eq(approvals.orgId, orgId), eq(approvals.status, "pending"));
1387
1524
  const [summaryRows, latestApprovalRows, latestCommentRows, unreadRows] = await Promise.all([
1388
1525
  db
@@ -1390,11 +1527,11 @@ export function messengerService(db) {
1390
1527
  itemCount: sql `count(*)::int`,
1391
1528
  })
1392
1529
  .from(approvals)
1393
- .where(approvalPredicate),
1530
+ .where(pendingApprovalPredicate),
1394
1531
  db
1395
1532
  .select()
1396
1533
  .from(approvals)
1397
- .where(approvalPredicate)
1534
+ .where(pendingApprovalPredicate)
1398
1535
  .orderBy(desc(approvals.updatedAt), desc(approvals.createdAt))
1399
1536
  .limit(1),
1400
1537
  db
@@ -1416,6 +1553,7 @@ export function messengerService(db) {
1416
1553
  limit 1
1417
1554
  ) latest_comment on true
1418
1555
  where ${approvals.orgId} = ${orgId}
1556
+ and ${approvals.status} = 'pending'
1419
1557
  order by latest_comment.created_at desc
1420
1558
  limit 1
1421
1559
  `),
@@ -1444,7 +1582,7 @@ export function messengerService(db) {
1444
1582
  ? await db
1445
1583
  .select()
1446
1584
  .from(approvals)
1447
- .where(and(eq(approvals.id, latestCommentRow.approvalId), approvalPredicate))
1585
+ .where(and(eq(approvals.id, latestCommentRow.approvalId), pendingApprovalPredicate))
1448
1586
  .limit(1)
1449
1587
  : [];
1450
1588
  const candidateItems = [];
@@ -1907,6 +2045,7 @@ export function messengerService(db) {
1907
2045
  return {
1908
2046
  listCustomGroups,
1909
2047
  createCustomGroup,
2048
+ createCustomGroupWithEntries,
1910
2049
  updateCustomGroup,
1911
2050
  separateCustomGroup,
1912
2051
  deleteCustomGroup,